Skip to content

Instantly share code, notes, and snippets.

@kynx
Created September 16, 2022 10:51
Show Gist options
  • Save kynx/96a3bb44d5f3ee4510e0fd8c65576e6b to your computer and use it in GitHub Desktop.
Save kynx/96a3bb44d5f3ee4510e0fd8c65576e6b to your computer and use it in GitHub Desktop.
Psalm config for detecting unsafe array access when migrating PHP7 - 8
<?xml version="1.0"?>
<psalm
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
errorLevel="1"
phpVersion="8.0"
ensureArrayStringOffsetsExist="true"
ensureArrayIntOffsetsExist="true"
>
<projectFiles>
<directory name="src"/>
<ignoreFiles>
<directory name="vendor"/>
</ignoreFiles>
</projectFiles>
<issueHandlers>
<AbstractInstantiation errorLevel="suppress"/>
<AbstractMethodCall errorLevel="suppress"/>
<ArgumentTypeCoercion errorLevel="suppress"/>
<AssignmentToVoid errorLevel="suppress"/>
<CircularReference errorLevel="suppress"/>
<ComplexFunction errorLevel="suppress"/>
<ComplexMethod errorLevel="suppress"/>
<ConfigIssue errorLevel="suppress"/>
<ConflictingReferenceConstraint errorLevel="suppress"/>
<ConstructorSignatureMismatch errorLevel="suppress"/>
<ContinueOutsideLoop errorLevel="suppress"/>
<DeprecatedClass errorLevel="suppress"/>
<DeprecatedConstant errorLevel="suppress"/>
<DeprecatedFunction errorLevel="suppress"/>
<DeprecatedInterface errorLevel="suppress"/>
<DeprecatedMethod errorLevel="suppress"/>
<DeprecatedProperty errorLevel="suppress"/>
<DeprecatedTrait errorLevel="suppress"/>
<DocblockTypeContradiction errorLevel="suppress"/>
<DuplicateArrayKey errorLevel="suppress"/>
<DuplicateClass errorLevel="suppress"/>
<DuplicateConstant errorLevel="suppress"/>
<DuplicateEnumCase errorLevel="suppress"/>
<DuplicateEnumCaseValue errorLevel="suppress"/>
<DuplicateFunction errorLevel="suppress"/>
<DuplicateMethod errorLevel="suppress"/>
<DuplicateParam errorLevel="suppress"/>
<EmptyArrayAccess errorLevel="suppress"/>
<ExtensionRequirementViolation errorLevel="suppress"/>
<FalsableReturnStatement errorLevel="suppress"/>
<FalseOperand errorLevel="suppress"/>
<ForbiddenCode errorLevel="suppress"/>
<ForbiddenEcho errorLevel="suppress"/>
<IfThisIsMismatch errorLevel="suppress"/>
<ImplementationRequirementViolation errorLevel="suppress"/>
<ImplementedParamTypeMismatch errorLevel="suppress"/>
<ImplementedReturnTypeMismatch errorLevel="suppress"/>
<ImplicitToStringCast errorLevel="suppress"/>
<ImpureByReferenceAssignment errorLevel="suppress"/>
<ImpureFunctionCall errorLevel="suppress"/>
<ImpureMethodCall errorLevel="suppress"/>
<ImpurePropertyAssignment errorLevel="suppress"/>
<ImpurePropertyFetch errorLevel="suppress"/>
<ImpureStaticProperty errorLevel="suppress"/>
<ImpureStaticVariable errorLevel="suppress"/>
<ImpureVariable errorLevel="suppress"/>
<InaccessibleClassConstant errorLevel="suppress"/>
<InaccessibleMethod errorLevel="suppress"/>
<InaccessibleProperty errorLevel="suppress"/>
<InterfaceInstantiation errorLevel="suppress"/>
<InternalClass errorLevel="suppress"/>
<InternalMethod errorLevel="suppress"/>
<InternalProperty errorLevel="suppress"/>
<InvalidArgument errorLevel="suppress"/>
<!-- <InvalidArrayAccess errorLevel="suppress"/>-->
<InvalidArrayAssignment errorLevel="suppress"/>
<InvalidArrayOffset errorLevel="suppress"/>
<InvalidAttribute errorLevel="suppress"/>
<InvalidCast errorLevel="suppress"/>
<InvalidCatch errorLevel="suppress"/>
<InvalidClass errorLevel="suppress"/>
<InvalidClone errorLevel="suppress"/>
<InvalidDocblock errorLevel="suppress"/>
<InvalidDocblockParamName errorLevel="suppress"/>
<InvalidEnumBackingType errorLevel="suppress"/>
<InvalidEnumCaseValue errorLevel="suppress"/>
<InvalidExtendClass errorLevel="suppress"/>
<InvalidFalsableReturnType errorLevel="suppress"/>
<InvalidFunctionCall errorLevel="suppress"/>
<InvalidGlobal errorLevel="suppress"/>
<InvalidIterator errorLevel="suppress"/>
<InvalidLiteralArgument errorLevel="suppress"/>
<InvalidMethodCall errorLevel="suppress"/>
<InvalidNamedArgument errorLevel="suppress"/>
<InvalidNullableReturnType errorLevel="suppress"/>
<InvalidOperand errorLevel="suppress"/>
<InvalidParamDefault errorLevel="suppress"/>
<InvalidParent errorLevel="suppress"/>
<InvalidPassByReference errorLevel="suppress"/>
<InvalidPropertyAssignment errorLevel="suppress"/>
<InvalidPropertyAssignmentValue errorLevel="suppress"/>
<InvalidPropertyFetch errorLevel="suppress"/>
<InvalidReturnStatement errorLevel="suppress"/>
<InvalidReturnType errorLevel="suppress"/>
<InvalidScalarArgument errorLevel="suppress"/>
<InvalidScope errorLevel="suppress"/>
<InvalidStaticInvocation errorLevel="suppress"/>
<InvalidStringClass errorLevel="suppress"/>
<InvalidTemplateParam errorLevel="suppress"/>
<InvalidThrow errorLevel="suppress"/>
<InvalidToString errorLevel="suppress"/>
<InvalidTraversableImplementation errorLevel="suppress"/>
<InvalidTypeImport errorLevel="suppress"/>
<LessSpecificImplementedReturnType errorLevel="suppress"/>
<LessSpecificReturnStatement errorLevel="suppress"/>
<LessSpecificReturnType errorLevel="suppress"/>
<LoopInvalidation errorLevel="suppress"/>
<MethodSignatureMismatch errorLevel="suppress"/>
<MethodSignatureMustOmitReturnType errorLevel="suppress"/>
<MethodSignatureMustProvideReturnType errorLevel="suppress"/>
<MismatchingDocblockParamType errorLevel="suppress"/>
<MismatchingDocblockPropertyType errorLevel="suppress"/>
<MismatchingDocblockReturnType errorLevel="suppress"/>
<MissingClosureParamType errorLevel="suppress"/>
<MissingClosureReturnType errorLevel="suppress"/>
<MissingConstructor errorLevel="suppress"/>
<MissingDependency errorLevel="suppress"/>
<MissingDocblockType errorLevel="suppress"/>
<MissingFile errorLevel="suppress"/>
<MissingImmutableAnnotation errorLevel="suppress"/>
<MissingParamType errorLevel="suppress"/>
<MissingPropertyType errorLevel="suppress"/>
<MissingReturnType errorLevel="suppress"/>
<MissingTemplateParam errorLevel="suppress"/>
<MissingThrowsDocblock errorLevel="suppress"/>
<MixedArgument errorLevel="suppress"/>
<MixedArgumentTypeCoercion errorLevel="suppress"/>
<MixedArrayAccess errorLevel="suppress"/>
<MixedArrayAssignment errorLevel="suppress"/>
<MixedArrayOffset errorLevel="suppress"/>
<MixedArrayTypeCoercion errorLevel="suppress"/>
<MixedAssignment errorLevel="suppress"/>
<MixedClone errorLevel="suppress"/>
<MixedFunctionCall errorLevel="suppress"/>
<MixedInferredReturnType errorLevel="suppress"/>
<MixedMethodCall errorLevel="suppress"/>
<MixedOperand errorLevel="suppress"/>
<MixedPropertyAssignment errorLevel="suppress"/>
<MixedPropertyFetch errorLevel="suppress"/>
<MixedPropertyTypeCoercion errorLevel="suppress"/>
<MixedReturnStatement errorLevel="suppress"/>
<MixedReturnTypeCoercion errorLevel="suppress"/>
<MixedStringOffsetAssignment errorLevel="suppress"/>
<MoreSpecificImplementedParamType errorLevel="suppress"/>
<MoreSpecificReturnType errorLevel="suppress"/>
<MutableDependency errorLevel="suppress"/>
<NamedArgumentNotAllowed errorLevel="suppress"/>
<NoEnumProperties errorLevel="suppress"/>
<NoInterfaceProperties errorLevel="suppress"/>
<NoValue errorLevel="suppress"/>
<NonInvariantDocblockPropertyType errorLevel="suppress"/>
<NonInvariantPropertyType errorLevel="suppress"/>
<NonStaticSelfCall errorLevel="suppress"/>
<NullArgument errorLevel="suppress"/>
<!-- <NullArrayAccess errorLevel="suppress"/>-->
<NullArrayOffset errorLevel="suppress"/>
<NullFunctionCall errorLevel="suppress"/>
<NullIterator errorLevel="suppress"/>
<NullOperand errorLevel="suppress"/>
<NullPropertyAssignment errorLevel="suppress"/>
<NullPropertyFetch errorLevel="suppress"/>
<NullReference errorLevel="suppress"/>
<NullableReturnStatement errorLevel="suppress"/>
<OverriddenMethodAccess errorLevel="suppress"/>
<OverriddenPropertyAccess errorLevel="suppress"/>
<ParadoxicalCondition errorLevel="suppress"/>
<ParamNameMismatch errorLevel="suppress"/>
<ParentNotFound errorLevel="suppress"/>
<PossibleRawObjectIteration errorLevel="suppress"/>
<PossiblyFalseArgument errorLevel="suppress"/>
<PossiblyFalseIterator errorLevel="suppress"/>
<PossiblyFalseOperand errorLevel="suppress"/>
<PossiblyFalsePropertyAssignmentValue errorLevel="suppress"/>
<PossiblyFalseReference errorLevel="suppress"/>
<PossiblyInvalidArgument errorLevel="suppress"/>
<PossiblyInvalidArrayAccess errorLevel="suppress"/>
<PossiblyInvalidArrayAssignment errorLevel="suppress"/>
<!-- <PossiblyInvalidArrayOffset errorLevel="suppress"/>-->
<PossiblyInvalidCast errorLevel="suppress"/>
<PossiblyInvalidClone errorLevel="suppress"/>
<PossiblyInvalidDocblockTag errorLevel="suppress"/>
<PossiblyInvalidFunctionCall errorLevel="suppress"/>
<PossiblyInvalidIterator errorLevel="suppress"/>
<PossiblyInvalidMethodCall errorLevel="suppress"/>
<PossiblyInvalidOperand errorLevel="suppress"/>
<PossiblyInvalidPropertyAssignment errorLevel="suppress"/>
<PossiblyInvalidPropertyAssignmentValue errorLevel="suppress"/>
<PossiblyInvalidPropertyFetch errorLevel="suppress"/>
<PossiblyNullArgument errorLevel="suppress"/>
<!-- <PossiblyNullArrayAccess errorLevel="suppress"/>-->
<PossiblyNullArrayAssignment errorLevel="suppress"/>
<PossiblyNullArrayOffset errorLevel="suppress"/>
<PossiblyNullFunctionCall errorLevel="suppress"/>
<PossiblyNullIterator errorLevel="suppress"/>
<PossiblyNullOperand errorLevel="suppress"/>
<PossiblyNullPropertyAssignment errorLevel="suppress"/>
<PossiblyNullPropertyAssignmentValue errorLevel="suppress"/>
<PossiblyNullPropertyFetch errorLevel="suppress"/>
<PossiblyNullReference errorLevel="suppress"/>
<!-- <PossiblyUndefinedArrayOffset errorLevel="suppress"/>-->
<PossiblyUndefinedGlobalVariable errorLevel="suppress"/>
<!-- <PossiblyUndefinedIntArrayOffset errorLevel="suppress"/>-->
<PossiblyUndefinedMethod errorLevel="suppress"/>
<!-- <PossiblyUndefinedStringArrayOffset errorLevel="suppress"/>-->
<PossiblyUndefinedVariable errorLevel="suppress"/>
<PossiblyUnusedMethod errorLevel="suppress"/>
<PossiblyUnusedParam errorLevel="suppress"/>
<PossiblyUnusedProperty errorLevel="suppress"/>
<PossiblyUnusedReturnValue errorLevel="suppress"/>
<PropertyNotSetInConstructor errorLevel="suppress"/>
<PropertyTypeCoercion errorLevel="suppress"/>
<RawObjectIteration errorLevel="suppress"/>
<RedundantCast errorLevel="suppress"/>
<RedundantCastGivenDocblockType errorLevel="suppress"/>
<RedundantCondition errorLevel="suppress"/>
<RedundantConditionGivenDocblockType errorLevel="suppress"/>
<RedundantFunctionCall errorLevel="suppress"/>
<RedundantFunctionCallGivenDocblockType errorLevel="suppress"/>
<RedundantIdentityWithTrue errorLevel="suppress"/>
<RedundantPropertyInitializationCheck errorLevel="suppress"/>
<ReferenceConstraintViolation errorLevel="suppress"/>
<ReservedWord errorLevel="suppress"/>
<StringIncrement errorLevel="suppress"/>
<TaintedCallable errorLevel="suppress"/>
<TaintedCookie errorLevel="suppress"/>
<TaintedCustom errorLevel="suppress"/>
<TaintedEval errorLevel="suppress"/>
<TaintedFile errorLevel="suppress"/>
<TaintedHeader errorLevel="suppress"/>
<TaintedHtml errorLevel="suppress"/>
<TaintedInclude errorLevel="suppress"/>
<TaintedInput errorLevel="suppress"/>
<TaintedLdap errorLevel="suppress"/>
<TaintedSSRF errorLevel="suppress"/>
<TaintedShell errorLevel="suppress"/>
<TaintedSql errorLevel="suppress"/>
<TaintedSystemSecret errorLevel="suppress"/>
<TaintedTextWithQuotes errorLevel="suppress"/>
<TaintedUnserialize errorLevel="suppress"/>
<TaintedUserSecret errorLevel="suppress"/>
<TooFewArguments errorLevel="suppress"/>
<TooManyArguments errorLevel="suppress"/>
<TooManyTemplateParams errorLevel="suppress"/>
<Trace errorLevel="suppress"/>
<TraitMethodSignatureMismatch errorLevel="suppress"/>
<TypeDoesNotContainNull errorLevel="suppress"/>
<TypeDoesNotContainType errorLevel="suppress"/>
<UncaughtThrowInGlobalScope errorLevel="suppress"/>
<UndefinedAttributeClass errorLevel="suppress"/>
<UndefinedClass errorLevel="suppress"/>
<UndefinedConstant errorLevel="suppress"/>
<UndefinedDocblockClass errorLevel="suppress"/>
<UndefinedFunction errorLevel="suppress"/>
<UndefinedGlobalVariable errorLevel="suppress"/>
<UndefinedInterface errorLevel="suppress"/>
<UndefinedInterfaceMethod errorLevel="suppress"/>
<UndefinedMagicMethod errorLevel="suppress"/>
<UndefinedMagicPropertyAssignment errorLevel="suppress"/>
<UndefinedMagicPropertyFetch errorLevel="suppress"/>
<UndefinedMethod errorLevel="suppress"/>
<UndefinedPropertyAssignment errorLevel="suppress"/>
<UndefinedPropertyFetch errorLevel="suppress"/>
<UndefinedThisPropertyAssignment errorLevel="suppress"/>
<UndefinedThisPropertyFetch errorLevel="suppress"/>
<UndefinedTrace errorLevel="suppress"/>
<UndefinedTrait errorLevel="suppress"/>
<UndefinedVariable errorLevel="suppress"/>
<UnevaluatedCode errorLevel="suppress"/>
<UnhandledMatchCondition errorLevel="suppress"/>
<UnimplementedAbstractMethod errorLevel="suppress"/>
<UnimplementedInterfaceMethod errorLevel="suppress"/>
<UninitializedProperty errorLevel="suppress"/>
<UnnecessaryVarAnnotation errorLevel="suppress"/>
<UnrecognizedExpression errorLevel="suppress"/>
<UnrecognizedStatement errorLevel="suppress"/>
<UnresolvableInclude errorLevel="suppress"/>
<UnsafeGenericInstantiation errorLevel="suppress"/>
<UnsafeInstantiation errorLevel="suppress"/>
<UnusedClass errorLevel="suppress"/>
<UnusedClosureParam errorLevel="suppress"/>
<UnusedConstructor errorLevel="suppress"/>
<UnusedForeachValue errorLevel="suppress"/>
<UnusedFunctionCall errorLevel="suppress"/>
<UnusedMethod errorLevel="suppress"/>
<UnusedMethodCall errorLevel="suppress"/>
<UnusedParam errorLevel="suppress"/>
<UnusedProperty errorLevel="suppress"/>
<UnusedPsalmSuppress errorLevel="suppress"/>
<UnusedReturnValue errorLevel="suppress"/>
<UnusedVariable errorLevel="suppress"/>
</issueHandlers>
</psalm>
@kynx
Copy link
Author

kynx commented Sep 16, 2022

PHP8 promotes undefined array offset errors from E_NOTICE to E_WARNING, which breaks a lot of legacy code that was ignoring notices (yeah, bad bad bad 😉 )

The idea here is to detect absolutely all errors (errorLevel="1", ensureArrayStringOffsetsExist="true", etc), but then use <issueHandlers> to suppress everything except the array offset stuff. It's a useful technique that can be used when hunting for other categories of issues in legacy code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment