1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Reflection;
4:
5: use PhpParser\Node;
6: use PHPStan\Analyser\Scope;
7: use PHPStan\Parser\ArrayFilterArgVisitor;
8: use PHPStan\Parser\ArrayMapArgVisitor;
9: use PHPStan\Parser\ArrayWalkArgVisitor;
10: use PHPStan\Parser\CurlSetOptArgVisitor;
11: use PHPStan\Reflection\Native\NativeParameterReflection;
12: use PHPStan\Reflection\Php\DummyParameter;
13: use PHPStan\Reflection\Php\DummyParameterWithPhpDocs;
14: use PHPStan\ShouldNotHappenException;
15: use PHPStan\TrinaryLogic;
16: use PHPStan\Type\Accessory\AccessoryNonEmptyStringType;
17: use PHPStan\Type\ArrayType;
18: use PHPStan\Type\BooleanType;
19: use PHPStan\Type\CallableType;
20: use PHPStan\Type\Constant\ConstantIntegerType;
21: use PHPStan\Type\ErrorType;
22: use PHPStan\Type\Generic\TemplateType;
23: use PHPStan\Type\Generic\TemplateTypeMap;
24: use PHPStan\Type\IntegerType;
25: use PHPStan\Type\LateResolvableType;
26: use PHPStan\Type\MixedType;
27: use PHPStan\Type\NullType;
28: use PHPStan\Type\ResourceType;
29: use PHPStan\Type\StringType;
30: use PHPStan\Type\Type;
31: use PHPStan\Type\TypeCombinator;
32: use PHPStan\Type\TypeTraverser;
33: use PHPStan\Type\UnionType;
34: use function array_key_last;
35: use function array_map;
36: use function array_slice;
37: use function constant;
38: use function count;
39: use function defined;
40: use function sprintf;
41: use const ARRAY_FILTER_USE_BOTH;
42: use const ARRAY_FILTER_USE_KEY;
43: use const CURLOPT_SSL_VERIFYHOST;
44:
45: /** @api */
46: class ParametersAcceptorSelector
47: {
48:
49: /**
50: * @template T of ParametersAcceptor
51: * @param T[] $parametersAcceptors
52: * @return T
53: */
54: public static function selectSingle(
55: array $parametersAcceptors,
56: ): ParametersAcceptor
57: {
58: $count = count($parametersAcceptors);
59: if ($count === 0) {
60: throw new ShouldNotHappenException(
61: 'getVariants() must return at least one variant.',
62: );
63: }
64: if ($count !== 1) {
65: throw new ShouldNotHappenException('Multiple variants - use selectFromArgs() instead.');
66: }
67:
68: return $parametersAcceptors[0];
69: }
70:
71: /**
72: * @param Node\Arg[] $args
73: * @param ParametersAcceptor[] $parametersAcceptors
74: */
75: public static function selectFromArgs(
76: Scope $scope,
77: array $args,
78: array $parametersAcceptors,
79: ): ParametersAcceptor
80: {
81: $types = [];
82: $unpack = false;
83: if (
84: count($args) > 0
85: && count($parametersAcceptors) > 0
86: ) {
87: $arrayMapArgs = $args[0]->value->getAttribute(ArrayMapArgVisitor::ATTRIBUTE_NAME);
88: if ($arrayMapArgs !== null) {
89: $acceptor = $parametersAcceptors[0];
90: $parameters = $acceptor->getParameters();
91: $callbackParameters = [];
92: foreach ($arrayMapArgs as $arg) {
93: $callbackParameters[] = new DummyParameter('item', self::getIterableValueType($scope->getType($arg->value)), false, PassedByReference::createNo(), false, null);
94: }
95: $parameters[0] = new NativeParameterReflection(
96: $parameters[0]->getName(),
97: $parameters[0]->isOptional(),
98: new UnionType([
99: new CallableType($callbackParameters, new MixedType(), false),
100: new NullType(),
101: ]),
102: $parameters[0]->passedByReference(),
103: $parameters[0]->isVariadic(),
104: $parameters[0]->getDefaultValue(),
105: );
106: $parametersAcceptors = [
107: new FunctionVariant(
108: $acceptor->getTemplateTypeMap(),
109: $acceptor->getResolvedTemplateTypeMap(),
110: $parameters,
111: $acceptor->isVariadic(),
112: $acceptor->getReturnType(),
113: ),
114: ];
115: }
116:
117: if (count($args) >= 3 && (bool) $args[0]->getAttribute(CurlSetOptArgVisitor::ATTRIBUTE_NAME)) {
118: $optType = $scope->getType($args[1]->value);
119: if ($optType instanceof ConstantIntegerType) {
120: $optValueType = self::getCurlOptValueType($optType->getValue());
121:
122: if ($optValueType !== null) {
123: $acceptor = $parametersAcceptors[0];
124: $parameters = $acceptor->getParameters();
125:
126: $parameters[2] = new NativeParameterReflection(
127: $parameters[2]->getName(),
128: $parameters[2]->isOptional(),
129: $optValueType,
130: $parameters[2]->passedByReference(),
131: $parameters[2]->isVariadic(),
132: $parameters[2]->getDefaultValue(),
133: );
134:
135: $parametersAcceptors = [
136: new FunctionVariant(
137: $acceptor->getTemplateTypeMap(),
138: $acceptor->getResolvedTemplateTypeMap(),
139: $parameters,
140: $acceptor->isVariadic(),
141: $acceptor->getReturnType(),
142: ),
143: ];
144: }
145: }
146: }
147:
148: if (isset($args[0]) && (bool) $args[0]->getAttribute(ArrayFilterArgVisitor::ATTRIBUTE_NAME)) {
149: if (isset($args[2])) {
150: $mode = $scope->getType($args[2]->value);
151: if ($mode instanceof ConstantIntegerType) {
152: if ($mode->getValue() === ARRAY_FILTER_USE_KEY) {
153: $arrayFilterParameters = [
154: new DummyParameter('key', self::getIterableKeyType($scope->getType($args[0]->value)), false, PassedByReference::createNo(), false, null),
155: ];
156: } elseif ($mode->getValue() === ARRAY_FILTER_USE_BOTH) {
157: $arrayFilterParameters = [
158: new DummyParameter('item', self::getIterableValueType($scope->getType($args[0]->value)), false, PassedByReference::createNo(), false, null),
159: new DummyParameter('key', self::getIterableKeyType($scope->getType($args[0]->value)), false, PassedByReference::createNo(), false, null),
160: ];
161: }
162: }
163: }
164:
165: $acceptor = $parametersAcceptors[0];
166: $parameters = $acceptor->getParameters();
167: $parameters[1] = new NativeParameterReflection(
168: $parameters[1]->getName(),
169: $parameters[1]->isOptional(),
170: new CallableType(
171: $arrayFilterParameters ?? [
172: new DummyParameter('item', self::getIterableValueType($scope->getType($args[0]->value)), false, PassedByReference::createNo(), false, null),
173: ],
174: new MixedType(),
175: false,
176: ),
177: $parameters[1]->passedByReference(),
178: $parameters[1]->isVariadic(),
179: $parameters[1]->getDefaultValue(),
180: );
181: $parametersAcceptors = [
182: new FunctionVariant(
183: $acceptor->getTemplateTypeMap(),
184: $acceptor->getResolvedTemplateTypeMap(),
185: $parameters,
186: $acceptor->isVariadic(),
187: $acceptor->getReturnType(),
188: ),
189: ];
190: }
191:
192: if (isset($args[0]) && (bool) $args[0]->getAttribute(ArrayWalkArgVisitor::ATTRIBUTE_NAME)) {
193: $arrayWalkParameters = [
194: new DummyParameter('item', self::getIterableValueType($scope->getType($args[0]->value)), false, PassedByReference::createReadsArgument(), false, null),
195: new DummyParameter('key', self::getIterableKeyType($scope->getType($args[0]->value)), false, PassedByReference::createNo(), false, null),
196: ];
197: if (isset($args[2])) {
198: $arrayWalkParameters[] = new DummyParameter('arg', $scope->getType($args[2]->value), false, PassedByReference::createNo(), false, null);
199: }
200:
201: $acceptor = $parametersAcceptors[0];
202: $parameters = $acceptor->getParameters();
203: $parameters[1] = new NativeParameterReflection(
204: $parameters[1]->getName(),
205: $parameters[1]->isOptional(),
206: new CallableType($arrayWalkParameters, new MixedType(), false),
207: $parameters[1]->passedByReference(),
208: $parameters[1]->isVariadic(),
209: $parameters[1]->getDefaultValue(),
210: );
211: $parametersAcceptors = [
212: new FunctionVariant(
213: $acceptor->getTemplateTypeMap(),
214: $acceptor->getResolvedTemplateTypeMap(),
215: $parameters,
216: $acceptor->isVariadic(),
217: $acceptor->getReturnType(),
218: ),
219: ];
220: }
221: }
222:
223: if (count($parametersAcceptors) === 1) {
224: $acceptor = $parametersAcceptors[0];
225: if (!self::hasAcceptorTemplateOrLateResolvableType($acceptor)) {
226: return $acceptor;
227: }
228: }
229:
230: foreach ($args as $i => $arg) {
231: $type = $scope->getType($arg->value);
232: $index = $arg->name !== null ? $arg->name->toString() : $i;
233: if ($arg->unpack) {
234: $unpack = true;
235: $types[$index] = $type->getIterableValueType();
236: } else {
237: $types[$index] = $type;
238: }
239: }
240:
241: return self::selectFromTypes($types, $parametersAcceptors, $unpack);
242: }
243:
244: private static function hasAcceptorTemplateOrLateResolvableType(ParametersAcceptor $acceptor): bool
245: {
246: if (self::hasTemplateOrLateResolvableType($acceptor->getReturnType())) {
247: return true;
248: }
249:
250: foreach ($acceptor->getParameters() as $parameter) {
251: if (!self::hasTemplateOrLateResolvableType($parameter->getType())) {
252: continue;
253: }
254:
255: return true;
256: }
257:
258: return false;
259: }
260:
261: private static function hasTemplateOrLateResolvableType(Type $type): bool
262: {
263: $has = false;
264: TypeTraverser::map($type, static function (Type $type, callable $traverse) use (&$has): Type {
265: if ($type instanceof TemplateType || $type instanceof LateResolvableType) {
266: $has = true;
267: return $type;
268: }
269:
270: return $traverse($type);
271: });
272:
273: return $has;
274: }
275:
276: /**
277: * @param array<int|string, Type> $types
278: * @param ParametersAcceptor[] $parametersAcceptors
279: */
280: public static function selectFromTypes(
281: array $types,
282: array $parametersAcceptors,
283: bool $unpack,
284: ): ParametersAcceptor
285: {
286: if (count($parametersAcceptors) === 1) {
287: return GenericParametersAcceptorResolver::resolve($types, $parametersAcceptors[0]);
288: }
289:
290: if (count($parametersAcceptors) === 0) {
291: throw new ShouldNotHappenException(
292: 'getVariants() must return at least one variant.',
293: );
294: }
295:
296: $typesCount = count($types);
297: $acceptableAcceptors = [];
298:
299: foreach ($parametersAcceptors as $parametersAcceptor) {
300: if ($unpack) {
301: $acceptableAcceptors[] = $parametersAcceptor;
302: continue;
303: }
304:
305: $functionParametersMinCount = 0;
306: $functionParametersMaxCount = 0;
307: foreach ($parametersAcceptor->getParameters() as $parameter) {
308: if (!$parameter->isOptional()) {
309: $functionParametersMinCount++;
310: }
311:
312: $functionParametersMaxCount++;
313: }
314:
315: if ($typesCount < $functionParametersMinCount) {
316: continue;
317: }
318:
319: if (
320: !$parametersAcceptor->isVariadic()
321: && $typesCount > $functionParametersMaxCount
322: ) {
323: continue;
324: }
325:
326: $acceptableAcceptors[] = $parametersAcceptor;
327: }
328:
329: if (count($acceptableAcceptors) === 0) {
330: return GenericParametersAcceptorResolver::resolve($types, self::combineAcceptors($parametersAcceptors));
331: }
332:
333: if (count($acceptableAcceptors) === 1) {
334: return GenericParametersAcceptorResolver::resolve($types, $acceptableAcceptors[0]);
335: }
336:
337: $winningAcceptors = [];
338: $winningCertainty = null;
339: foreach ($acceptableAcceptors as $acceptableAcceptor) {
340: $isSuperType = TrinaryLogic::createYes();
341: $acceptableAcceptor = GenericParametersAcceptorResolver::resolve($types, $acceptableAcceptor);
342: foreach ($acceptableAcceptor->getParameters() as $i => $parameter) {
343: if (!isset($types[$i])) {
344: if (!$unpack || count($types) <= 0) {
345: break;
346: }
347:
348: $type = $types[array_key_last($types)];
349: } else {
350: $type = $types[$i];
351: }
352:
353: if ($parameter->getType() instanceof MixedType) {
354: $isSuperType = $isSuperType->and(TrinaryLogic::createMaybe());
355: } else {
356: $isSuperType = $isSuperType->and($parameter->getType()->isSuperTypeOf($type));
357: }
358: }
359:
360: if ($isSuperType->no()) {
361: continue;
362: }
363:
364: if ($winningCertainty === null) {
365: $winningAcceptors[] = $acceptableAcceptor;
366: $winningCertainty = $isSuperType;
367: } else {
368: $comparison = $winningCertainty->compareTo($isSuperType);
369: if ($comparison === $isSuperType) {
370: $winningAcceptors = [$acceptableAcceptor];
371: $winningCertainty = $isSuperType;
372: } elseif ($comparison === null) {
373: $winningAcceptors[] = $acceptableAcceptor;
374: }
375: }
376: }
377:
378: if (count($winningAcceptors) === 0) {
379: return GenericParametersAcceptorResolver::resolve($types, self::combineAcceptors($acceptableAcceptors));
380: }
381:
382: return GenericParametersAcceptorResolver::resolve($types, self::combineAcceptors($winningAcceptors));
383: }
384:
385: /**
386: * @param ParametersAcceptor[] $acceptors
387: */
388: public static function combineAcceptors(array $acceptors): ParametersAcceptorWithPhpDocs
389: {
390: if (count($acceptors) === 0) {
391: throw new ShouldNotHappenException(
392: 'getVariants() must return at least one variant.',
393: );
394: }
395: if (count($acceptors) === 1) {
396: return self::wrapAcceptor($acceptors[0]);
397: }
398:
399: $minimumNumberOfParameters = null;
400: foreach ($acceptors as $acceptor) {
401: $acceptorParametersMinCount = 0;
402: foreach ($acceptor->getParameters() as $parameter) {
403: if ($parameter->isOptional()) {
404: continue;
405: }
406:
407: $acceptorParametersMinCount++;
408: }
409:
410: if ($minimumNumberOfParameters !== null && $minimumNumberOfParameters <= $acceptorParametersMinCount) {
411: continue;
412: }
413:
414: $minimumNumberOfParameters = $acceptorParametersMinCount;
415: }
416:
417: $parameters = [];
418: $isVariadic = false;
419: $returnType = null;
420: $phpDocReturnType = null;
421: $nativeReturnType = null;
422:
423: foreach ($acceptors as $acceptor) {
424: if ($returnType === null) {
425: $returnType = $acceptor->getReturnType();
426: } else {
427: $returnType = TypeCombinator::union($returnType, $acceptor->getReturnType());
428: }
429: if ($acceptor instanceof ParametersAcceptorWithPhpDocs) {
430: if ($phpDocReturnType === null) {
431: $phpDocReturnType = $acceptor->getPhpDocReturnType();
432: } else {
433: $phpDocReturnType = TypeCombinator::union($phpDocReturnType, $acceptor->getPhpDocReturnType());
434: }
435: }
436: if ($acceptor instanceof ParametersAcceptorWithPhpDocs) {
437: if ($nativeReturnType === null) {
438: $nativeReturnType = $acceptor->getNativeReturnType();
439: } else {
440: $nativeReturnType = TypeCombinator::union($nativeReturnType, $acceptor->getNativeReturnType());
441: }
442: }
443: $isVariadic = $isVariadic || $acceptor->isVariadic();
444:
445: foreach ($acceptor->getParameters() as $i => $parameter) {
446: if (!isset($parameters[$i])) {
447: $parameters[$i] = new DummyParameterWithPhpDocs(
448: $parameter->getName(),
449: $parameter->getType(),
450: $i + 1 > $minimumNumberOfParameters,
451: $parameter->passedByReference(),
452: $parameter->isVariadic(),
453: $parameter->getDefaultValue(),
454: $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getNativeType() : new MixedType(),
455: $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getPhpDocType() : new MixedType(),
456: $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter->getOutType() : null,
457: );
458: continue;
459: }
460:
461: $isVariadic = $parameters[$i]->isVariadic() || $parameter->isVariadic();
462: $defaultValueLeft = $parameters[$i]->getDefaultValue();
463: $defaultValueRight = $parameter->getDefaultValue();
464: if ($defaultValueLeft !== null && $defaultValueRight !== null) {
465: $defaultValue = TypeCombinator::union($defaultValueLeft, $defaultValueRight);
466: } else {
467: $defaultValue = null;
468: }
469:
470: $type = TypeCombinator::union($parameters[$i]->getType(), $parameter->getType());
471: $nativeType = $parameters[$i]->getNativeType();
472: $phpDocType = $parameters[$i]->getPhpDocType();
473: $outType = $parameters[$i]->getOutType();
474: if ($parameter instanceof ParameterReflectionWithPhpDocs) {
475: $nativeType = TypeCombinator::union($nativeType, $parameter->getNativeType());
476: $phpDocType = TypeCombinator::union($phpDocType, $parameter->getPhpDocType());
477:
478: if ($parameter->getOutType() !== null) {
479: $outType = $outType === null ? null : TypeCombinator::union($outType, $parameter->getOutType());
480: } else {
481: $outType = null;
482: }
483: } else {
484: $nativeType = new MixedType();
485: $phpDocType = $type;
486: $outType = null;
487: }
488:
489: $parameters[$i] = new DummyParameterWithPhpDocs(
490: $parameters[$i]->getName() !== $parameter->getName() ? sprintf('%s|%s', $parameters[$i]->getName(), $parameter->getName()) : $parameter->getName(),
491: $type,
492: $i + 1 > $minimumNumberOfParameters,
493: $parameters[$i]->passedByReference()->combine($parameter->passedByReference()),
494: $isVariadic,
495: $defaultValue,
496: $nativeType,
497: $phpDocType,
498: $outType,
499: );
500:
501: if ($isVariadic) {
502: $parameters = array_slice($parameters, 0, $i + 1);
503: break;
504: }
505: }
506: }
507:
508: return new FunctionVariantWithPhpDocs(
509: TemplateTypeMap::createEmpty(),
510: null,
511: $parameters,
512: $isVariadic,
513: $returnType,
514: $phpDocReturnType ?? $returnType,
515: $nativeReturnType ?? new MixedType(),
516: );
517: }
518:
519: private static function wrapAcceptor(ParametersAcceptor $acceptor): ParametersAcceptorWithPhpDocs
520: {
521: if ($acceptor instanceof ParametersAcceptorWithPhpDocs) {
522: return $acceptor;
523: }
524:
525: return new FunctionVariantWithPhpDocs(
526: $acceptor->getTemplateTypeMap(),
527: $acceptor->getResolvedTemplateTypeMap(),
528: array_map(static fn (ParameterReflection $parameter): ParameterReflectionWithPhpDocs => self::wrapParameter($parameter), $acceptor->getParameters()),
529: $acceptor->isVariadic(),
530: $acceptor->getReturnType(),
531: $acceptor->getReturnType(),
532: new MixedType(),
533: );
534: }
535:
536: private static function wrapParameter(ParameterReflection $parameter): ParameterReflectionWithPhpDocs
537: {
538: return $parameter instanceof ParameterReflectionWithPhpDocs ? $parameter : new DummyParameterWithPhpDocs(
539: $parameter->getName(),
540: $parameter->getType(),
541: $parameter->isOptional(),
542: $parameter->passedByReference(),
543: $parameter->isVariadic(),
544: $parameter->getDefaultValue(),
545: new MixedType(),
546: $parameter->getType(),
547: null,
548: );
549: }
550:
551: private static function getIterableValueType(Type $type): Type
552: {
553: if ($type instanceof UnionType) {
554: $types = [];
555: foreach ($type->getTypes() as $innerType) {
556: $iterableValueType = $innerType->getIterableValueType();
557: if ($iterableValueType instanceof ErrorType) {
558: continue;
559: }
560:
561: $types[] = $iterableValueType;
562: }
563:
564: return TypeCombinator::union(...$types);
565: }
566:
567: return $type->getIterableValueType();
568: }
569:
570: private static function getIterableKeyType(Type $type): Type
571: {
572: if ($type instanceof UnionType) {
573: $types = [];
574: foreach ($type->getTypes() as $innerType) {
575: $iterableKeyType = $innerType->getIterableKeyType();
576: if ($iterableKeyType instanceof ErrorType) {
577: continue;
578: }
579:
580: $types[] = $iterableKeyType;
581: }
582:
583: return TypeCombinator::union(...$types);
584: }
585:
586: return $type->getIterableKeyType();
587: }
588:
589: private static function getCurlOptValueType(int $curlOpt): ?Type
590: {
591: if (defined('CURLOPT_SSL_VERIFYHOST') && $curlOpt === CURLOPT_SSL_VERIFYHOST) {
592: return new UnionType([new ConstantIntegerType(0), new ConstantIntegerType(2)]);
593: }
594:
595: $boolConstants = [
596: 'CURLOPT_AUTOREFERER',
597: 'CURLOPT_COOKIESESSION',
598: 'CURLOPT_CERTINFO',
599: 'CURLOPT_CONNECT_ONLY',
600: 'CURLOPT_CRLF',
601: 'CURLOPT_DISALLOW_USERNAME_IN_URL',
602: 'CURLOPT_DNS_SHUFFLE_ADDRESSES',
603: 'CURLOPT_HAPROXYPROTOCOL',
604: 'CURLOPT_SSH_COMPRESSION',
605: 'CURLOPT_DNS_USE_GLOBAL_CACHE',
606: 'CURLOPT_FAILONERROR',
607: 'CURLOPT_SSL_FALSESTART',
608: 'CURLOPT_FILETIME',
609: 'CURLOPT_FOLLOWLOCATION',
610: 'CURLOPT_FORBID_REUSE',
611: 'CURLOPT_FRESH_CONNECT',
612: 'CURLOPT_FTP_USE_EPRT',
613: 'CURLOPT_FTP_USE_EPSV',
614: 'CURLOPT_FTP_CREATE_MISSING_DIRS',
615: 'CURLOPT_FTPAPPEND',
616: 'CURLOPT_TCP_NODELAY',
617: 'CURLOPT_FTPASCII',
618: 'CURLOPT_FTPLISTONLY',
619: 'CURLOPT_HEADER',
620: 'CURLOPT_HTTP09_ALLOWED',
621: 'CURLOPT_HTTPGET',
622: 'CURLOPT_HTTPPROXYTUNNEL',
623: 'CURLOPT_HTTP_CONTENT_DECODING',
624: 'CURLOPT_KEEP_SENDING_ON_ERROR',
625: 'CURLOPT_MUTE',
626: 'CURLOPT_NETRC',
627: 'CURLOPT_NOBODY',
628: 'CURLOPT_NOPROGRESS',
629: 'CURLOPT_NOSIGNAL',
630: 'CURLOPT_PATH_AS_IS',
631: 'CURLOPT_PIPEWAIT',
632: 'CURLOPT_POST',
633: 'CURLOPT_PUT',
634: 'CURLOPT_RETURNTRANSFER',
635: 'CURLOPT_SASL_IR',
636: 'CURLOPT_SSL_ENABLE_ALPN',
637: 'CURLOPT_SSL_ENABLE_NPN',
638: 'CURLOPT_SSL_VERIFYPEER',
639: 'CURLOPT_SSL_VERIFYSTATUS',
640: 'CURLOPT_PROXY_SSL_VERIFYPEER',
641: 'CURLOPT_SUPPRESS_CONNECT_HEADERS',
642: 'CURLOPT_TCP_FASTOPEN',
643: 'CURLOPT_TFTP_NO_OPTIONS',
644: 'CURLOPT_TRANSFERTEXT',
645: 'CURLOPT_UNRESTRICTED_AUTH',
646: 'CURLOPT_UPLOAD',
647: 'CURLOPT_VERBOSE',
648: ];
649: foreach ($boolConstants as $constName) {
650: if (defined($constName) && constant($constName) === $curlOpt) {
651: return new BooleanType();
652: }
653: }
654:
655: $intConstants = [
656: 'CURLOPT_BUFFERSIZE',
657: 'CURLOPT_CONNECTTIMEOUT',
658: 'CURLOPT_CONNECTTIMEOUT_MS',
659: 'CURLOPT_DNS_CACHE_TIMEOUT',
660: 'CURLOPT_EXPECT_100_TIMEOUT_MS',
661: 'CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS',
662: 'CURLOPT_FTPSSLAUTH',
663: 'CURLOPT_HEADEROPT',
664: 'CURLOPT_HTTP_VERSION',
665: 'CURLOPT_HTTPAUTH',
666: 'CURLOPT_INFILESIZE',
667: 'CURLOPT_LOW_SPEED_LIMIT',
668: 'CURLOPT_LOW_SPEED_TIME',
669: 'CURLOPT_MAXCONNECTS',
670: 'CURLOPT_MAXREDIRS',
671: 'CURLOPT_PORT',
672: 'CURLOPT_POSTREDIR',
673: 'CURLOPT_PROTOCOLS',
674: 'CURLOPT_PROXYAUTH',
675: 'CURLOPT_PROXYPORT',
676: 'CURLOPT_PROXYTYPE',
677: 'CURLOPT_REDIR_PROTOCOLS',
678: 'CURLOPT_RESUME_FROM',
679: 'CURLOPT_SOCKS5_AUTH',
680: 'CURLOPT_SSL_OPTIONS',
681: 'CURLOPT_SSL_VERIFYHOST',
682: 'CURLOPT_SSLVERSION',
683: 'CURLOPT_PROXY_SSL_OPTIONS',
684: 'CURLOPT_PROXY_SSL_VERIFYHOST',
685: 'CURLOPT_PROXY_SSLVERSION',
686: 'CURLOPT_STREAM_WEIGHT',
687: 'CURLOPT_TCP_KEEPALIVE',
688: 'CURLOPT_TCP_KEEPIDLE',
689: 'CURLOPT_TCP_KEEPINTVL',
690: 'CURLOPT_TIMECONDITION',
691: 'CURLOPT_TIMEOUT',
692: 'CURLOPT_TIMEOUT_MS',
693: 'CURLOPT_TIMEVALUE',
694: 'CURLOPT_TIMEVALUE_LARGE',
695: 'CURLOPT_MAX_RECV_SPEED_LARGE',
696: 'CURLOPT_SSH_AUTH_TYPES',
697: 'CURLOPT_IPRESOLVE',
698: 'CURLOPT_FTP_FILEMETHOD',
699: ];
700: foreach ($intConstants as $constName) {
701: if (defined($constName) && constant($constName) === $curlOpt) {
702: return new IntegerType();
703: }
704: }
705:
706: $nonEmptyStringConstants = [
707: 'CURLOPT_ABSTRACT_UNIX_SOCKET',
708: 'CURLOPT_CAINFO',
709: 'CURLOPT_CAPATH',
710: 'CURLOPT_COOKIE',
711: 'CURLOPT_COOKIEJAR',
712: 'CURLOPT_COOKIELIST',
713: 'CURLOPT_CUSTOMREQUEST',
714: 'CURLOPT_DEFAULT_PROTOCOL',
715: 'CURLOPT_DNS_INTERFACE',
716: 'CURLOPT_DNS_LOCAL_IP4',
717: 'CURLOPT_DNS_LOCAL_IP6',
718: 'CURLOPT_EGDSOCKET',
719: 'CURLOPT_FTPPORT',
720: 'CURLOPT_INTERFACE',
721: 'CURLOPT_KEYPASSWD',
722: 'CURLOPT_KRB4LEVEL',
723: 'CURLOPT_LOGIN_OPTIONS',
724: 'CURLOPT_PINNEDPUBLICKEY',
725: 'CURLOPT_PROXY_SERVICE_NAME',
726: 'CURLOPT_PROXY_CAINFO',
727: 'CURLOPT_PROXY_CAPATH',
728: 'CURLOPT_PROXY_CRLFILE',
729: 'CURLOPT_PROXY_KEYPASSWD',
730: 'CURLOPT_PROXY_PINNEDPUBLICKEY',
731: 'CURLOPT_PROXY_SSLCERT',
732: 'CURLOPT_PROXY_SSLCERTTYPE',
733: 'CURLOPT_PROXY_SSL_CIPHER_LIST',
734: 'CURLOPT_PROXY_TLS13_CIPHERS',
735: 'CURLOPT_PROXY_SSLKEY',
736: 'CURLOPT_PROXY_SSLKEYTYPE',
737: 'CURLOPT_PROXY_TLSAUTH_PASSWORD',
738: 'CURLOPT_PROXY_TLSAUTH_TYPE',
739: 'CURLOPT_PROXY_TLSAUTH_USERNAME',
740: 'CURLOPT_PROXYUSERPWD',
741: 'CURLOPT_RANDOM_FILE',
742: 'CURLOPT_RANGE',
743: 'CURLOPT_REFERER',
744: 'CURLOPT_SERVICE_NAME',
745: 'CURLOPT_SSH_HOST_PUBLIC_KEY_MD5',
746: 'CURLOPT_SSH_PUBLIC_KEYFILE',
747: 'CURLOPT_SSH_PRIVATE_KEYFILE',
748: 'CURLOPT_SSL_CIPHER_LIST',
749: 'CURLOPT_SSLCERT',
750: 'CURLOPT_SSLCERTPASSWD',
751: 'CURLOPT_SSLCERTTYPE',
752: 'CURLOPT_SSLENGINE',
753: 'CURLOPT_SSLENGINE_DEFAULT',
754: 'CURLOPT_SSLKEY',
755: 'CURLOPT_SSLKEYPASSWD',
756: 'CURLOPT_SSLKEYTYPE',
757: 'CURLOPT_TLS13_CIPHERS',
758: 'CURLOPT_UNIX_SOCKET_PATH',
759: 'CURLOPT_URL',
760: 'CURLOPT_USERAGENT',
761: 'CURLOPT_USERNAME',
762: 'CURLOPT_PASSWORD',
763: 'CURLOPT_USERPWD',
764: 'CURLOPT_XOAUTH2_BEARER',
765: ];
766: foreach ($nonEmptyStringConstants as $constName) {
767: if (defined($constName) && constant($constName) === $curlOpt) {
768: return TypeCombinator::intersect(
769: new StringType(),
770: new AccessoryNonEmptyStringType(),
771: );
772: }
773: }
774:
775: $stringConstants = [
776: 'CURLOPT_COOKIEFILE',
777: 'CURLOPT_ENCODING',
778: 'CURLOPT_PRE_PROXY',
779: 'CURLOPT_PRIVATE',
780: 'CURLOPT_PROXY',
781: ];
782: foreach ($stringConstants as $constName) {
783: if (defined($constName) && constant($constName) === $curlOpt) {
784: return new StringType();
785: }
786: }
787:
788: $arrayConstants = [
789: 'CURLOPT_CONNECT_TO',
790: 'CURLOPT_HTTP200ALIASES',
791: 'CURLOPT_HTTPHEADER',
792: 'CURLOPT_POSTQUOTE',
793: 'CURLOPT_PROXYHEADER',
794: 'CURLOPT_QUOTE',
795: 'CURLOPT_RESOLVE',
796: ];
797: foreach ($arrayConstants as $constName) {
798: if (defined($constName) && constant($constName) === $curlOpt) {
799: return new ArrayType(new MixedType(), new MixedType());
800: }
801: }
802:
803: $arrayOrStringConstants = [
804: 'CURLOPT_POSTFIELDS',
805: ];
806: foreach ($arrayOrStringConstants as $constName) {
807: if (defined($constName) && constant($constName) === $curlOpt) {
808: return new UnionType([
809: new StringType(),
810: new ArrayType(new MixedType(), new MixedType()),
811: ]);
812: }
813: }
814:
815: $resourceConstants = [
816: 'CURLOPT_FILE',
817: 'CURLOPT_INFILE',
818: 'CURLOPT_STDERR',
819: 'CURLOPT_WRITEHEADER',
820: ];
821: foreach ($resourceConstants as $constName) {
822: if (defined($constName) && constant($constName) === $curlOpt) {
823: return new ResourceType();
824: }
825: }
826:
827: // unknown constant
828: return null;
829: }
830:
831: }
832: