@@ -206,7 +206,7 @@ public function tryToRepresentableType(): ?RepresentableType {
206
206
$ classType = $ type ;
207
207
} else {
208
208
// We can only represent a single class type.
209
- return false ;
209
+ return null ;
210
210
}
211
211
}
212
212
return new RepresentableType ($ classType , $ builtinTypes );
@@ -326,9 +326,17 @@ public function equals(ReturnInfo $other): bool {
326
326
class FuncInfo {
327
327
/** @var string */
328
328
public $ name ;
329
- /** @var ? string */
329
+ /** @var string|null */
330
330
public $ className ;
331
- /** @var ?string */
331
+ /** @var string|null */
332
+ public $ visibility ;
333
+ /** @var bool */
334
+ public $ isAbstract ;
335
+ /** @var bool */
336
+ public $ isStatic ;
337
+ /** @var bool */
338
+ public $ isFinal ;
339
+ /** @var string|null */
332
340
public $ alias ;
333
341
/** @var bool */
334
342
public $ isDeprecated ;
@@ -342,11 +350,25 @@ class FuncInfo {
342
350
public $ cond ;
343
351
344
352
public function __construct (
345
- string $ name , ?string $ className , ?string $ alias , bool $ isDeprecated , array $ args , ReturnInfo $ return ,
346
- int $ numRequiredArgs , ?string $ cond
353
+ string $ name ,
354
+ ?string $ className ,
355
+ ?string $ visibility ,
356
+ bool $ isAbstract ,
357
+ bool $ isStatic ,
358
+ bool $ isFinal ,
359
+ ?string $ alias ,
360
+ bool $ isDeprecated ,
361
+ array $ args ,
362
+ ReturnInfo $ return ,
363
+ int $ numRequiredArgs ,
364
+ ?string $ cond
347
365
) {
348
366
$ this ->name = $ name ;
349
367
$ this ->className = $ className ;
368
+ $ this ->visibility = $ visibility ;
369
+ $ this ->isAbstract = $ isAbstract ;
370
+ $ this ->isStatic = $ isStatic ;
371
+ $ this ->isFinal = $ isFinal ;
350
372
$ this ->alias = $ alias ;
351
373
$ this ->isDeprecated = $ isDeprecated ;
352
374
$ this ->args = $ args ;
@@ -377,6 +399,78 @@ public function getArgInfoName(): string {
377
399
}
378
400
return 'arginfo_ ' . $ this ->name ;
379
401
}
402
+
403
+ public function getFlags (): string
404
+ {
405
+ $ flags = sprintf ("ZEND_ACC_%s " , strtoupper ($ this ->visibility ));
406
+
407
+ if ($ this ->isStatic ) {
408
+ $ flags .= "|ZEND_ACC_STATIC " ;
409
+ }
410
+
411
+ if ($ this ->isFinal ) {
412
+ $ flags .= "|ZEND_ACC_FINAL " ;
413
+ }
414
+
415
+ if ($ this ->isAbstract ) {
416
+ $ flags .= "|ZEND_ACC_ABSTRACT " ;
417
+ }
418
+
419
+ if ($ this ->isDeprecated ) {
420
+ $ flags .= "|ZEND_ACC_DEPRECATED " ;
421
+ }
422
+
423
+ return $ flags ;
424
+ }
425
+
426
+ public function getDeclarationKey (): string
427
+ {
428
+ $ name = $ this ->alias ?? $ this ->name ;
429
+
430
+ return "$ name| $ this ->cond " ;
431
+ }
432
+
433
+ public function hasDeclaration (): bool
434
+ {
435
+ return $ this ->isAbstract === false || $ this ->visibility !== "public " ;
436
+ }
437
+
438
+ public function getDeclaration (): string
439
+ {
440
+ if ($ this ->hasDeclaration () === false ) {
441
+ return "" ;
442
+ }
443
+
444
+ if ($ this ->alias ) {
445
+ $ methodAlias = $ this ->getMethodAlias ();
446
+
447
+ if ($ methodAlias ) {
448
+ return "ZEND_METHOD( $ this ->className , $ methodAlias); \n" ;
449
+ } else {
450
+ return "ZEND_FUNCTION( $ this ->alias ); \n" ;
451
+ }
452
+ }
453
+
454
+ if ($ this ->className ) {
455
+ return "ZEND_METHOD( $ this ->className , $ this ->name ); \n" ;
456
+ }
457
+
458
+ return "ZEND_FUNCTION( $ this ->name ); \n" ;
459
+ }
460
+
461
+ public function getMethodAlias (): ?string
462
+ {
463
+ if ($ this ->className === false || $ this ->alias === null ) {
464
+ return null ;
465
+ }
466
+
467
+ $ separatorPosition = strpos ($ this ->alias , ":: " );
468
+ if ($ separatorPosition === false ) {
469
+ return null ;
470
+ }
471
+
472
+ return substr ($ this ->alias , $ separatorPosition );
473
+ }
380
474
}
381
475
382
476
class ClassInfo {
@@ -417,7 +511,7 @@ public function getAllFuncInfos(): iterable {
417
511
class DocCommentTag {
418
512
/** @var string */
419
513
public $ name ;
420
- /** @var ? string */
514
+ /** @var string|null */
421
515
public $ value ;
422
516
423
517
public function __construct (string $ name , ?string $ value ) {
@@ -458,7 +552,15 @@ function parseDocComment(DocComment $comment): array {
458
552
}
459
553
460
554
function parseFunctionLike (
461
- PrettyPrinterAbstract $ prettyPrinter , string $ name , ?string $ className , Node \FunctionLike $ func , ?string $ cond
555
+ PrettyPrinterAbstract $ prettyPrinter ,
556
+ string $ name ,
557
+ ?string $ className ,
558
+ ?string $ visibility ,
559
+ bool $ isAbstract ,
560
+ bool $ isStatic ,
561
+ bool $ isFinal ,
562
+ Node \FunctionLike $ func ,
563
+ ?string $ cond
462
564
): FuncInfo {
463
565
$ comment = $ func ->getDocComment ();
464
566
$ paramMeta = [];
@@ -539,8 +641,23 @@ function parseFunctionLike(
539
641
540
642
$ return = new ReturnInfo (
541
643
$ func ->returnsByRef (),
542
- $ returnType ? Type::fromNode ($ returnType ) : null );
543
- return new FuncInfo ($ name , $ className , $ alias , $ isDeprecated , $ args , $ return , $ numRequiredArgs , $ cond );
644
+ $ returnType ? Type::fromNode ($ returnType ) : null
645
+ );
646
+
647
+ return new FuncInfo (
648
+ $ name ,
649
+ $ className ,
650
+ $ visibility ,
651
+ $ isAbstract ,
652
+ $ isStatic ,
653
+ $ isFinal ,
654
+ $ alias ,
655
+ $ isDeprecated ,
656
+ $ args ,
657
+ $ return ,
658
+ $ numRequiredArgs ,
659
+ $ cond
660
+ );
544
661
}
545
662
546
663
function handlePreprocessorConditions (array &$ conds , Stmt $ stmt ): ?string {
@@ -622,7 +739,18 @@ function parseStubFile(string $fileName): FileInfo {
622
739
}
623
740
624
741
if ($ stmt instanceof Stmt \Function_) {
625
- $ funcInfos [] = parseFunctionLike ($ prettyPrinter , $ stmt ->name ->toString (), null , $ stmt , $ cond );
742
+ $ funcInfos [] = parseFunctionLike (
743
+ $ prettyPrinter ,
744
+ $ stmt ->name ->toString (),
745
+ null ,
746
+ null ,
747
+ false ,
748
+ false ,
749
+ false ,
750
+ $ stmt ,
751
+ $ cond
752
+ );
753
+
626
754
continue ;
627
755
}
628
756
@@ -639,8 +767,22 @@ function parseStubFile(string $fileName): FileInfo {
639
767
throw new Exception ("Not implemented {$ classStmt ->getType ()}" );
640
768
}
641
769
770
+ $ visibility = $ classStmt ->isPublic () ? "public " : ($ classStmt ->isProtected () ? "protected " : "private " );
771
+ $ isAbstract = $ classStmt ->isAbstract () || $ stmt instanceof Stmt \Interface_;
772
+ $ isStatic = $ classStmt ->isStatic ();
773
+ $ isFinal = $ classStmt ->isFinal ();
774
+
642
775
$ methodInfos [] = parseFunctionLike (
643
- $ prettyPrinter , $ classStmt ->name ->toString (), $ className , $ classStmt , $ cond );
776
+ $ prettyPrinter ,
777
+ $ classStmt ->name ->toString (),
778
+ $ className ,
779
+ $ visibility ,
780
+ $ isAbstract ,
781
+ $ isStatic ,
782
+ $ isFinal ,
783
+ $ classStmt ,
784
+ $ cond
785
+ );
644
786
}
645
787
646
788
$ classInfos [] = new ClassInfo ($ className , $ methodInfos );
@@ -746,7 +888,8 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
746
888
return $ code . "\n" ;
747
889
}
748
890
749
- function findEquivalentFuncInfo (array $ generatedFuncInfos , $ funcInfo ): ?FuncInfo {
891
+ /** @param FuncInfo[] $generatedFuncInfos */
892
+ function findEquivalentFuncInfo (array $ generatedFuncInfos , FuncInfo $ funcInfo ): ?FuncInfo {
750
893
foreach ($ generatedFuncInfos as $ generatedFuncInfo ) {
751
894
if ($ generatedFuncInfo ->equalsApartFromName ($ funcInfo )) {
752
895
return $ generatedFuncInfo ;
@@ -778,8 +921,6 @@ function generateCodeWithConditions(
778
921
}
779
922
780
923
function generateArgInfoCode (FileInfo $ fileInfo ): string {
781
- $ funcInfos = $ fileInfo ->funcInfos ;
782
-
783
924
$ code = "/* This is a generated file, edit the .stub.php file instead. */ \n" ;
784
925
$ generatedFuncInfos = [];
785
926
$ code .= generateCodeWithConditions (
@@ -801,21 +942,67 @@ function(FuncInfo $funcInfo) use(&$generatedFuncInfos) {
801
942
);
802
943
803
944
if ($ fileInfo ->generateFunctionEntries ) {
804
- $ code .= "\n\n" ;
805
- $ generatedDeclarations = [];
806
- $ code .= generateCodeWithConditions ($ funcInfos , "" , function (FuncInfo $ funcInfo ) use (&$ generatedDeclarations ) {
807
- $ name = $ funcInfo ->alias ?? $ funcInfo ->name ;
808
- $ key = "$ name| $ funcInfo ->cond " ;
809
- if (isset ($ generatedDeclarations [$ key ])) {
810
- return null ;
945
+ $ code .= generateFunctionEntry (null , $ fileInfo ->funcInfos );
946
+
947
+ foreach ($ fileInfo ->classInfos as $ classInfo ) {
948
+ $ code .= generateFunctionEntry ($ classInfo ->name , $ classInfo ->funcInfos );
949
+ }
950
+ }
951
+
952
+ return $ code ;
953
+ }
954
+
955
+ /** @param FuncInfo[] $funcInfos */
956
+ function generateFunctionEntry (?string $ className , array $ funcInfos ): string {
957
+ $ code = "" ;
958
+ $ generatedDeclarations = [];
959
+ $ code .= generateCodeWithConditions ($ funcInfos , "" , function (FuncInfo $ funcInfo ) use (&$ generatedDeclarations ) {
960
+ $ key = $ funcInfo ->getDeclarationKey ();
961
+ if (isset ($ generatedDeclarations [$ key ])) {
962
+ return null ;
963
+ }
964
+ $ generatedDeclarations [$ key ] = true ;
965
+
966
+ return $ funcInfo ->getDeclaration ();
967
+ });
968
+
969
+ if ($ code ) {
970
+ $ code = "\n\n" . $ code ;
971
+ }
972
+
973
+ $ functionEntryName = $ className ? "class_ {$ className }_methods " : "ext_functions " ;
974
+
975
+ $ code .= "\n\nstatic const zend_function_entry {$ functionEntryName }[] = { \n" ;
976
+ $ code .= generateCodeWithConditions ($ funcInfos , "" , function (FuncInfo $ funcInfo ) {
977
+ if ($ funcInfo ->className ) {
978
+ if ($ funcInfo ->alias ) {
979
+ $ methodAlias = $ funcInfo ->getMethodAlias ();
980
+
981
+ if ($ methodAlias ) {
982
+ return sprintf (
983
+ "\tZEND_MALIAS(%s, %s, %s, %s, %s) \n" ,
984
+ $ funcInfo ->className , $ funcInfo ->name , $ methodAlias , $ funcInfo ->getArgInfoName (), $ funcInfo ->getFlags ()
985
+ );
986
+ }
987
+
988
+ return sprintf (
989
+ "\tZEND_ME_MAPPING(%s, %s, %s, %s) \n" ,
990
+ $ funcInfo ->name , $ funcInfo ->alias , $ funcInfo ->getArgInfoName (), $ funcInfo ->getFlags ()
991
+ );
811
992
}
812
993
813
- $ generatedDeclarations [$ key ] = true ;
814
- return "ZEND_FUNCTION( $ name); \n" ;
815
- });
994
+ if ($ funcInfo ->hasDeclaration () === false ) {
995
+ return sprintf (
996
+ "\tZEND_ABSTRACT_ME(%s, %s, %s) \n" ,
997
+ $ funcInfo ->className , $ funcInfo ->name , $ funcInfo ->getArgInfoName ()
998
+ );
999
+ }
816
1000
817
- $ code .= "\n\nstatic const zend_function_entry ext_functions[] = { \n" ;
818
- $ code .= generateCodeWithConditions ($ fileInfo ->funcInfos , "" , function (FuncInfo $ funcInfo ) {
1001
+ return sprintf (
1002
+ "\tZEND_ME(%s, %s, %s, %s) \n" ,
1003
+ $ funcInfo ->className , $ funcInfo ->name , $ funcInfo ->getArgInfoName (), $ funcInfo ->getFlags ()
1004
+ );
1005
+ } else {
819
1006
if ($ funcInfo ->alias ) {
820
1007
return sprintf (
821
1008
"\tZEND_FALIAS(%s, %s, %s) \n" ,
@@ -828,10 +1015,10 @@ function(FuncInfo $funcInfo) use(&$generatedFuncInfos) {
828
1015
}
829
1016
830
1017
return sprintf ("\tZEND_FE(%s, %s) \n" , $ funcInfo ->name , $ funcInfo ->getArgInfoName ());
831
- });
832
- $ code .= "\t ZEND_FE_END \n" ;
833
- $ code .= "}; \n" ;
834
- }
1018
+ }
1019
+ }) ;
1020
+ $ code .= "\t ZEND_FE_END \n" ;
1021
+ $ code .= " }; \n" ;
835
1022
836
1023
return $ code ;
837
1024
}
0 commit comments