HTTP Saber (Da Mao Wang) ซึ่งเป็นไคลเอ็นต์ HTTP ประสิทธิภาพสูงของ PHP ของ Swoole人性化组件库
อิงตาม Coroutine ดั้งเดิมของ Swoole รองรับการทำงานหลายรูปแบบ และมอบโซลูชันประสิทธิภาพสูงที่ด้านล่าง ช่วยให้นักพัฒนามุ่งเน้นไปที่ฟังก์ชันการทำงานได้ การพัฒนาจากแบบดั้งเดิมฟรีจากการบล็อกแบบซิงโครนัสและการกำหนดค่าที่ยุ่งยากของ Curl
เอกสารภาษาอังกฤษ
วิธีที่ดีที่สุดในการติดตั้งคือผ่านตัวจัดการแพ็คเกจ Composer:
composer require swlib/saber
เลเยอร์ด้านล่างของ Swoole ใช้การตั้งเวลา coroutine และ เลเยอร์ธุรกิจไม่จำเป็นต้องระวัง นักพัฒนาสามารถ ใช้การเขียนโค้ดแบบซิงโครนัสเพื่อให้ได้ผลของ IO แบบอะซิงโครนัสและประสิทธิภาพที่สูงเป็นพิเศษ โดยไม่ต้องรับรู้ โดยหลีกเลี่ยงตรรกะของโค้ดที่ไม่ต่อเนื่องและ การดักจับที่มากเกินไปเกิดจากการเรียกกลับแบบอะซิงโครนัสแบบดั้งเดิมทำให้โค้ดไม่สามารถบำรุงรักษาได้
จำเป็นต้องใช้ใน onRequet
, onReceive
, onConnect
และฟังก์ชันการเรียกกลับเหตุการณ์อื่น ๆ หรือห่อด้วยคีย์เวิร์ด go ( swoole.use_shortname
ถูกเปิดใช้งานตามค่าเริ่มต้น)
go ( function () {
echo SaberGM:: get ( ' http://httpbin.org/get ' );
})
การบรรจุข้อมูลอัตโนมัติ: ข้อมูลขาเข้าจะถูกแปลงเป็นรูปแบบประเภทที่ระบุตามประเภทเนื้อหาโดยอัตโนมัติ
ค่าเริ่มต้นคือ
x-www-form-urlencoded
และรองรับรูปแบบอื่นๆ เช่นjson
ด้วยเช่นกัน
SaberGM
:= Saber Global Manager
หากคุณคิดว่าชื่อคลาสยาวสักหน่อย คุณสามารถใช้ class_alias
เพื่อตั้งชื่อแทนของคุณเองได้ ขอแนะนำให้ใช้วิธี การสร้างอินสแตนซ์ ในบริการและใช้ SaberGM
เป็นทางลัด
SaberGM:: get ( ' http://httpbin.org/get ' );
SaberGM:: delete ( ' http://httpbin.org/delete ' );
SaberGM:: post ( ' http://httpbin.org/post ' , [ ' foo ' => ' bar ' ]);
SaberGM:: put ( ' http://httpbin.org/put ' , [ ' foo ' => ' bar ' ]);
SaberGM:: patch ( ' http://httpbin.org/patch ' , [ ' foo ' => ' bar ' ]);
บริการพร็อกซี API ที่ใช้งานได้
$ saber = Saber:: create ([
' base_uri ' => ' http://httpbin.org ' ,
' headers ' => [
' Accept-Language ' => ' en,zh-CN;q=0.9,zh;q=0.8 ' ,
' Content-Type ' => ContentType:: JSON ,
' DNT ' => ' 1 ' ,
' User-Agent ' => null
]
]);
echo $ saber -> get ( ' /get ' );
echo $ saber -> delete ( ' /delete ' );
echo $ saber -> post ( ' /post ' , [ ' foo ' => ' bar ' ]);
echo $ saber -> patch ( ' /patch ' , [ ' foo ' => ' bar ' ]);
echo $ saber -> put ( ' /put ' , [ ' foo ' => ' bar ' ]);
เซสชันจะบันทึกข้อมูลคุกกี้โดยอัตโนมัติ และการใช้งานจะ เสร็จสมบูรณ์ในระดับเบราว์เซอร์
$ session = Saber:: session ([
' base_uri ' => ' http://httpbin.org ' ,
' redirect ' => 0
]);
$ session -> get ( ' /cookies/set?foo=bar&k=v&apple=banana ' );
$ session -> get ( ' /cookies/delete?k ' );
echo $ session -> get ( ' /cookies ' )-> body ;
หมายเหตุ: มีการใช้โซลูชันการปรับให้เหมาะสมการเปลี่ยนเส้นทางพร้อมกันที่นี่ การเปลี่ยนเส้นทางหลายรายการจะเกิดขึ้นพร้อมกันเสมอและจะไม่ทำให้กลายเป็นคำขอเดียวในคิว
$ responses = SaberGM:: requests ([
[ ' uri ' => ' http://github.com/ ' ],
[ ' uri ' => ' http://github.com/ ' ],
[ ' uri ' => ' https://github.com/ ' ]
]);
echo " multi-requests [ { $ responses -> success_num } ok, { $ responses -> error_num } error ]: n" . " consuming-time: { $ responses -> time } s n" ;
// multi - requests [ 3 ok , 0 error ] :
// consuming - time : 0 . 79090881347656s
// 别名机制可以省略参数书写参数名
$ saber = Saber:: create ([ ' base_uri ' => ' http://httpbin.org ' ]);
echo $ saber -> requests ([
[ ' get ' , ' /get ' ],
[ ' post ' , ' /post ' ],
[ ' patch ' , ' /patch ' ],
[ ' put ' , ' /put ' ],
[ ' delete ' , ' /delete ' ]
]);
ปัจจุบันรองรับการแยกวิเคราะห์ข้อมูลอย่างรวดเร็วในสี่รูปแบบ: json
, xml
, html
และ url-query
[ $ json , $ xml , $ html ] = SaberGM:: list ([
' uri ' => [
' http://httpbin.org/get ' ,
' http://www.w3school.com.cn/example/xmle/note.xml ' ,
' http://httpbin.org/html '
]
]);
var_dump ( $ json -> getParsedJsonArray ());
var_dump ( $ json -> getParsedJsonObject ());
var_dump ( $ xml -> getParsedXmlArray ());
var_dump ( $ xml -> getParsedXmlObject ( true ));
var_dump ( $ html -> getParsedDomObject ()-> getElementsByTagName ( ' h1 ' )-> item ( 0 )-> textContent );
รองรับพร็อกซี HTTP และ SOCKS5
$ uri = ' http://myip.ipip.net/ ' ;
echo SaberGM:: get ( $ uri , [ ' proxy ' => ' http://127.0.0.1:1087 ' ])-> body ;
echo SaberGM:: get ( $ uri , [ ' proxy ' => ' socks5://127.0.0.1:1086 ' ])-> body ;
การตั้งเวลา Coroutine อัตโนมัติที่รองรับ การส่งไฟล์ขนาดใหญ่มากแบบอะซิงโครนัส และ ดำเนินการอัปโหลดต่อที่จุดพัก
อัปโหลดสามไฟล์ในเวลาเดียวกัน (สามรูปแบบพารามิเตอร์
string
|array
|object
)
$ file1 = __DIR__ . ' /black.png ' ;
$ file2 = [
' path ' => __DIR__ . ' /black.png ' ,
' name ' => ' white.png ' ,
' type ' => ContentType:: MAP [ ' png ' ],
' offset ' => null , // re - upload from break
' size ' => null //upload a part of the file
];
$ file3 = new SwUploadFile (
__DIR__ . ' /black.png ' ,
' white.png ' ,
ContentType:: MAP [ ' png ' ]
);
echo SaberGM:: post ( ' http://httpbin.org/post ' , null , [
' files ' => [
' image1 ' => $ file1 ,
' image2 ' => $ file2 ,
' image3 ' => $ file3
]
]
);
หลังจากที่ Download ได้รับข้อมูลแล้ว มันจะเขียนลงดิสก์โดยตรงแบบอะซิงโครนัส แทนที่จะเชื่อมต่อ HttpBody ในหน่วยความจำ ดังนั้น การดาวน์โหลดจะใช้ หน่วยความจำเพียงเล็กน้อย เท่านั้นในการดาวน์โหลด ไฟล์ขนาดใหญ่มาก ให้เสร็จสมบูรณ์ นอกจากนี้ยังรองรับการดาวน์โหลด ต่อแบบเบรกพอยต์ ด้วย การตั้งค่าพารามิเตอร์ออฟเซ็ตเพื่อทำการดาวน์โหลดเบรกพอยต์
การดาวน์โหลดวอลเปเปอร์ Sabre แบบอะซิงโครนัส
$ download_dir = ' /tmp/saber.jpg ' ;
$ response = SaberGM:: download (
' https://ws1.sinaimg.cn/large/006DQdzWly1fsr8jt2botj31hc0wxqfs.jpg ' ,
$ download_dir
);
if ( $ response -> success ) {
exec ( ' open ' . $ download_dir );
}
ในโปรเจ็กต์ของโปรแกรมรวบรวมข้อมูล เป็นข้อกำหนดทั่วไปที่ต้องลองคำขอที่ล้มเหลวอีกครั้งโดยอัตโนมัติ เช่น เข้าสู่ระบบอีกครั้งหลังจากเซสชันหมดอายุ
Saber
มีฟังก์ชันนี้ในตัว และ拦截器
สามารถใช้เพื่อเพิ่มประสิทธิภาพได้
หากไม่ได้ตั้ง retry_time
แต่มีการตั้งค่า retry
interceptor ไว้ retry_time
จะถูกตั้งค่าเป็น 1 หากวิธีการเรียกกลับของ retry
interceptor ส่งคืน false
ไม่ว่า retry_time
จะเป็นเท่าใด การลองใหม่จะสิ้นสุดลงเมื่อส่งคืน false
$ uri = ' http://eu.httpbin.org/basic-auth/foo/bar ' ;
$ res = SaberGM:: get (
$ uri , [
' exception_report ' => 0 ,
' retry_time ' => 3 ,
' retry ' => function ( Saber Request $ request ) {
echo " retry... n" ;
$ request -> withBasicAuth ( ' foo ' , ' bar ' ); //发现失败后添加验证信息
if ( ' i don not want to retry again ' ) {
return false ; // shutdown
}
}
]
);
echo $ res ;
บางครั้งทรัพยากร HTTP ไม่ได้เปลี่ยนแปลงเสมอไป เราสามารถเรียนรู้ว่าเบราว์เซอร์แคชทรัพยากรที่ไม่เปลี่ยนแปลงเพื่อเร่งประสิทธิภาพคำขอได้อย่างไร Saber
ดำเนินการนี้โดยอัตโนมัติโดยไม่ต้องรักษาตรรกะแคช (CURD หรือการอ่านและเขียนไฟล์) ด้วยตัวเอง มันจะไม่บล็อกเซิร์ฟเวอร์อยู่ดี Saber
ไม่ได้ใช้กลไกมิดเดิลแวร์เนื่องจากมีความเกี่ยวข้องอย่างมากกับ Swoole แต่การแคชสามารถใช้内存/文件/数据库
และวิธีการอื่น ๆ ดังนั้นแม้ว่าจะยังไม่ได้ใช้งาน แต่จะรวมอยู่ใน Saber
แผนงานต่อไปของ
$ bufferStream = new BufferStream ();
$ bufferStream -> write ( json_encode ([ ' foo ' => ' bar ' ]));
$ response = SaberGM:: psr ()
-> withMethod ( ' POST ' )
-> withUri ( new Uri ( ' http://httpbin.org/post?foo=bar ' ))
-> withQueryParams ([ ' foo ' => ' option is higher-level than uri ' ])
-> withHeader ( ' content-type ' , ContentType:: JSON )
-> withBody ( $ bufferStream )
-> exec ()-> recv ();
echo $ response -> getBody ();
คุณสามารถพิมพ์สตริงข้อมูลที่ส่งคืนได้โดยตรงผ่านวิธี __toString ของเฟรมข้อมูล websocketFrame
$ websocket = SaberGM:: websocket ( ' ws://127.0.0.1:9999 ' );
while ( true ) {
echo $ websocket -> recv ( 1 ) . "n" ;
$ websocket -> push ( " hello " );
co:: sleep ( 1 );
}
เครื่องทดสอบคือ MacBook Pro ที่มีการกำหนดค่าต่ำที่สุด และเซิร์ฟเวอร์คำขอคือเซิร์ฟเวอร์ Echo ในเครื่อง
เสร็จสิ้นคำขอ 6,666 รายการใน 0.9 วินาที ด้วยอัตราความสำเร็จ 100%
co:: set ([ ' max_coroutine ' => 8191 ]);
go ( function () {
$ requests = [];
for ( $ i = 6666 ; $ i --;) {
$ requests [] = [ ' uri ' => ' http://127.0.0.1 ' ];
}
$ res = SaberGM:: requests ( $ requests );
echo " use { $ res -> time } s n" ;
echo " success: $ res -> success_num , error: $ res -> error_num " ;
});
// on MacOS
// use 0 . 91531705856323s
// success : 6666 , error : 0
ในโครงการจริง รายการ URL มักจะใช้เพื่อกำหนดค่าคำขอ ดังนั้นจึงมีวิธีการแสดงรายการเพื่อความสะดวก:
echo SaberGM:: list ([
' uri ' => [
' https://www.qq.com/ ' ,
' https://www.baidu.com/ ' ,
' https://www.swoole.com/ ' ,
' http://httpbin.org/ '
]
]);
ในโปรเจ็กต์ซอฟต์แวร์รวบรวมข้อมูลจริง เรามักจะต้องจำกัดจำนวนคำขอที่เกิดขึ้นพร้อมกันเพื่อป้องกันไม่ให้ไฟร์วอลล์เซิร์ฟเวอร์บล็อก และพารามิเตอร์ max_co
ก็สามารถแก้ปัญหานี้ได้อย่างง่ายดาย max_co
จะพุชคำขอลงในคิวเป็นชุดตามขีดจำกัดสูงสุด และดำเนินการรับแพ็คเกจ
// max_co is the max number of concurrency request once , it ' s very useful to prevent server - waf limit .
$ requests = array_fill ( 0 , 10 , [ ' uri ' => ' https://www.qq.com/ ' ]);
echo SaberGM:: requests ( $ requests , [ ' max_co ' => 5 ])-> time . "n" ;
echo SaberGM:: requests ( $ requests , [ ' max_co ' => 1 ])-> time . "n" ;
เมื่อใช้ในเซิร์ฟเวอร์ที่มีหน่วยความจำ ต้องแน่ใจว่าได้เปิดใช้งานตัวเลือกพูลการเชื่อมต่อด้วยตนเอง :
$ swoole = Saber:: create ([
' base_uri ' => ' https://www.swoole.com/ ' ,
' use_pool ' => true
]);
เมื่อใช้ผ่านอินสแตนซ์นี้ คุณลักษณะพูลการเชื่อมต่อจะถูกเปิดใช้งาน กล่าวคือ ไคลเอนต์การเชื่อมต่อพื้นฐานกับเว็บไซต์ www.swoole.com
จะใช้พูลการเชื่อมต่อส่วนกลางเพื่อเข้าถึง หลีกเลี่ยงค่าใช้จ่ายในการสร้าง/เชื่อมต่อแต่ละครั้งที่มีการใช้งาน .
เมื่อพารามิเตอร์เป็น true
ความจุของพูลการเชื่อมต่อของเว็บไซต์จะ ไม่จำกัด โดยทั่วไปจะไม่มีปัญหา และพูลการเชื่อมต่อที่มีความจุไม่จำกัดจะมีประสิทธิภาพดีกว่า
แต่ถ้าคุณใช้เป็นบริการพร็อกซีของโปรแกรมรวบรวมข้อมูลและพบ คำขอจำนวนมาก จำนวนไคลเอ็นต์ในกลุ่มการเชื่อมต่อจะเพิ่มขึ้นอย่างควบคุมไม่ได้และรวดเร็ว แม้จะเกินจำนวนการเชื่อมต่อสูงสุดที่อนุญาตโดยเว็บไซต์ต้นทางที่คุณร้องขอในขณะนี้ก็ตาม คุณต้องตั้ง use_pool
เป็น ค่าในอุดมคติ (int) ในขณะนี้ เลเยอร์ด้านล่างจะใช้ Channel เป็นกลุ่มการเชื่อมต่อ เมื่อจำนวนไคลเอนต์ที่สร้างโดยพูลการเชื่อมต่อเกินจำนวนและไม่เพียงพอ coroutine ที่ต้องเข้าถึงไคลเอนต์จะถูกระงับ และรอให้โครูทีนใช้ไคลเอ็นต์เพื่อส่งคืนไคลเอ็นต์ แทบไม่มีการใช้ประสิทธิภาพในการรอและสลับโครูทีนเลย และเป็นโซลูชัน ขั้นสูงมาก
ควรสังเกตว่าพูลการเชื่อมต่อเชื่อมโยงกับ服务器IP+端口
นั่นคือหากคุณมีหลายอินสแตนซ์ที่เผชิญกับ服务器IP+端口
เดียวกัน พูลการเชื่อมต่อที่ใช้ระหว่างเซิร์ฟเวอร์เหล่านั้นก็จะเหมือนกันเช่นกัน
ดังนั้นเมื่อคุณสร้างอินสแตนซ์ของ服务器IP+端口
ซ้ำๆ use_pool
ที่ระบุโดยอินสแตนซ์ที่สร้างขึ้นใหม่จะได้รับอนุญาตให้เขียนทับค่าก่อนหน้า นั่นคือชั้นล่างสุดของพูลการเชื่อมต่อจะเปลี่ยนความจุโดยอัตโนมัติ เมื่อความจุเพิ่มขึ้น เลเยอร์ด้านล่างจะสร้างกลุ่มการเชื่อมต่อใหม่และถ่ายโอนลูกค้า เมื่อความจุลดลง ไคลเอนต์ส่วนเกินในกลุ่มการเชื่อมต่อจะถูกทำลายด้วย
นอกเหนือจากการจดจำการกำหนดค่าพูลการเชื่อมต่อแล้ว วิธีการจัดการข้อยกเว้นยังต้องสอดคล้องกับพฤติกรรมการเขียนโปรแกรมของคุณ การจัดการข้อยกเว้นเริ่มต้นของ Saber
ถือเป็น抛出异常
กระแสหลักและเข้มงวดที่สุด แต่ Saber
ยังสนับสนุนการใช้错误码
โดยไม่โต้ตอบ错误码
และ状态位
อาจสอดคล้องกับรสนิยมของหลาย ๆ คนมากกว่า
SaberGM:: exceptionReport ( 0 ); // 关闭抛出异常报告, 在业务代码之前注册即可全局生效
$ saber -> exceptionReport ( 0 ); //也可以单独设置某个实例
ในทำนองเดียวกัน การกำหนดค่าที่คุณต้องการสามารถกำหนดค่าล่วงหน้าก่อนรหัสธุรกิจ เช่น onWorkerStart
หรือแม้แต่ก่อนที่ swoole_server
จะเริ่มทำงานด้วยซ้ำ
SaberGM:: default ([
' exception_report ' => 0
' use_pool ' => true
]);
การกำหนดค่าตัวเลือกที่คุณต้องการเช่นนี้จะทำให้คุณได้รับประสบการณ์ที่ดีขึ้น!
go ( function (){
// your code with pool ...
saber_pool_release (); // and this script will exit
});
หากคุณใช้พูลการเชื่อมต่อในสคริปต์แบบครั้งเดียว เนื่องจากมีไคลเอ็นต์ Coroutine อยู่ในพูล จำนวนการอ้างอิงคือ 1 และไม่สามารถเผยแพร่ได้ ซึ่งจะทำให้ swoole อยู่ในลูปเหตุการณ์เสมอและสคริปต์ไม่สามารถออกจากคุณได้ จำเป็นต้องโทร saber_pool_release
หรือ saber_exit
หรือ swoole_event_exit
ด้วยตนเองเพื่อออกตามปกติ หรือคุณสามารถใช้ exit เพื่อบังคับออกจากสคริปต์ปัจจุบัน (อย่าใช้ exit ในเซิร์ฟเวอร์)
|
สัญลักษณ์แยกค่าเผื่อเลือกหลายค่า
สำคัญ | พิมพ์ | การแนะนำ | ตัวอย่าง | หมายเหตุ |
---|---|---|---|---|
protocol_version | เชือก | เวอร์ชันโปรโตคอล HTTP | 1.1 | HTTP2 ยังอยู่ระหว่างการวางแผน |
base_uri | เชือก | เส้นทางฐาน | http://httpbin.org | จะถูกรวมเข้ากับ uri ตาม rfc3986 |
ยูริ | เชือก | ตัวระบุทรัพยากร | http://httpbin.org/get | /get get | สามารถใช้ทั้งเส้นทางแบบสัมบูรณ์และแบบสัมพัทธ์ |
uri_query | สตริง | อาร์เรย์ | ขอข้อมูล | ['foo' => 'bar'] | ข้อมูลที่ไม่ใช่สตริงจะถูกแปลงโดยอัตโนมัติ |
วิธี | เชือก | วิธีการขอ | get |. post head patch put delete | ชั้นล่างสุดจะถูกแปลงเป็นตัวพิมพ์ใหญ่โดยอัตโนมัติ |
ส่วนหัว | อาร์เรย์ | ส่วนหัวของคำขอ | ['DNT' => '1'] | ['accept' => ['text/html'], ['application/xml']] | ชื่อฟิลด์ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ แต่กฎตัวพิมพ์ดั้งเดิมระหว่างการตั้งค่าจะยังคงอยู่ ค่าฟิลด์พื้นฐานแต่ละค่าจะถูกแบ่งออกเป็นอาร์เรย์โดยอัตโนมัติตาม PSR-7 |
คุกกี้ | array | string | ['foo '=> 'bar'] | 'foo=bar; foz=baz' | เลเยอร์ด้านล่างจะถูกแปลงเป็นออบเจ็กต์คุกกี้โดยอัตโนมัติ และโดเมนของเลเยอร์นั้นถูกตั้งค่าเป็น URI ปัจจุบัน พร้อมด้วยแอตทริบิวต์ที่สมบูรณ์ในระดับเบราว์เซอร์ | |
ตัวแทนผู้ใช้ | เชือก | ตัวแทนผู้ใช้ | curl-1.0 | ค่าเริ่มต้นคือ Chrome บนแพลตฟอร์ม Macos |
ผู้อ้างอิง | เชือก | ที่อยู่ต้นทาง | https://www.google.com | ค่าเริ่มต้นว่างเปล่า |
เปลี่ยนเส้นทาง | ภายใน | จำนวนการเปลี่ยนเส้นทางสูงสุด | 5 | ค่าเริ่มต้นคือ 3 และเมื่อเป็น 0 จะไม่มีการเปลี่ยนเส้นทาง |
ให้_มีชีวิตอยู่ | บูล | ไม่ว่าจะให้เชื่อมต่อ | true | false | ค่าเริ่มต้นคือ True การเชื่อมต่อจะถูกนำมาใช้ซ้ำโดยอัตโนมัติระหว่างการเปลี่ยนเส้นทาง |
content_type | เชือก | ส่งประเภทการเข้ารหัสเนื้อหาแล้ว | text/plain | SwlibHttpContentType::JSON | ค่าเริ่มต้นคือ application/x-www-form-urlencoded |
ข้อมูล | array | string | ส่งข้อมูลแล้ว | 'foo=bar&dog=cat' | ['foo' => 'bar'] | ข้อมูลจะถูกเข้ารหัสโดยอัตโนมัติตาม content_type |
ก่อน | callable array | ผู้สกัดกั้นคำขอล่วงหน้า | function(Request $request){} | โปรดดูส่วน Interceptor สำหรับรายละเอียด |
หลังจาก | callable array | ผู้สกัดกั้นหลังการตอบสนอง | function(Response $response){} | โปรดดูส่วน Interceptor สำหรับรายละเอียด |
before_redirect | callable array | ตัวดักหลังการเปลี่ยนเส้นทาง | function(Request $request, Response $response){} | โปรดดูส่วน Interceptor สำหรับรายละเอียด |
หมดเวลา | ลอย | หมดเวลา | 0.5 | ค่าเริ่มต้นคือ 5 วินาที รองรับการหมดเวลาเป็นมิลลิวินาที |
bind_address | เชือก | ผูกที่อยู่ | 192.168.1.1 หรือ eth0 | ไม่ได้ตั้งค่าไว้เป็นค่าเริ่มต้น |
ผูก_พอร์ต | ภายใน | ผูกพอร์ต | 80 | ไม่ได้ตั้งค่าไว้เป็นค่าเริ่มต้น |
พร็อกซี | เชือก | การแสดง | http://127.0.0.1:1087 |. socks5://127.0.0.1:1087 | รองรับ http และ Socks5 |
SSL | ภายใน | ไม่ว่าจะเปิดใช้งานการเชื่อมต่อ SSL | 0=关闭 1=开启 2=自动 | ค่าเริ่มต้นอัตโนมัติ |
แคไฟล์ | เชือก | ไฟล์แคลิฟอร์เนีย | __DIR__ . '/cacert.pem' | มาพร้อมกับค่าเริ่มต้น |
ssl_verify_peer | บูล | ตรวจสอบใบรับรองฝั่งเซิร์ฟเวอร์ | false | true | ปิดโดยค่าเริ่มต้น |
ssl_allow_self_signed | บูล | อนุญาตใบรับรองที่ลงนามด้วยตนเอง | true | false | อนุญาตตามค่าเริ่มต้น |
ssl_cert_file | เชือก | ใบรับรองใบรับรอง | __DIR__ . '/ssl.cert' | ไม่ได้ตั้งค่าไว้เป็นค่าเริ่มต้น |
ssl_key_file | เชือก | คีย์ส่วนตัว | __DIR__ . '/ssl.key' | ไม่ได้ตั้งค่าไว้เป็นค่าเริ่มต้น |
ไอคอนวี | อาร์เรย์ | ระบุการแปลงการเข้ารหัส | ['gbk', 'utf-8'] | มีทั้งหมดสามพารามิเตอร์: from,to,use_mb ซึ่งจะถูกจดจำโดยอัตโนมัติตามค่าเริ่มต้น |
ข้อยกเว้น_รายงาน | ภายใน | ระดับการรายงานข้อยกเว้น | HttpExceptionMask::E_ALL | รายงานข้อยกเว้นทั้งหมดตามค่าเริ่มต้น |
ข้อยกเว้น_การจัดการ | เรียกได้ | อาร์เรย์ | ฟังก์ชันการจัดการข้อยกเว้นแบบกำหนดเอง | function(Exception $e){} | ข้อผิดพลาดสามารถละเว้นได้เมื่อฟังก์ชันส่งคืนค่าจริง |
ลองอีกครั้ง | เรียกได้ | ตัวสกัดกั้นลองใหม่อัตโนมัติ | function(Request $request, Response $response){} | หลังจากเกิดข้อผิดพลาดและก่อนที่จะลองอีกครั้ง |
ลองอีกครั้ง_ครั้ง | ภายใน | จำนวนการลองใหม่อัตโนมัติ | อย่าลองใหม่ตามค่าเริ่มต้น | |
use_pool | บูล|int | พูลการเชื่อมต่อ | true | false |
pool_key | เรียกได้ | อาร์เรย์ | คีย์พูลการเชื่อมต่อ | function(Request $request):string { return $key; } | ค่าเริ่มต้นคือ host:port ของที่อยู่ที่ร้องขอ |
เพื่อความสะดวกในการใช้งานและความทนทานต่อข้อผิดพลาด ค่าคีย์ของรายการการกำหนดค่ามีกลไกนามแฝง ขอแนะนำให้ใช้ชื่อดั้งเดิมให้มากที่สุด:
สำคัญ | นามแฝง |
---|---|
วิธี | 0 |
ยูริ | 1 | url |
ข้อมูล | 2 |. body |
base_uri | base_url |
หลังจาก | โทรกลับ |
content_type | content-type | contentType |
คุกกี้ | คุกกี้ |
ส่วนหัว | ส่วนหัว |
เปลี่ยนเส้นทาง | ติดตาม |
ตัวแทนผู้ใช้ | ua | . user-agent |
ข้อยกเว้น_รายงาน | error_report | report |
before_retry | ลองอีกครั้ง |
ผู้อ้างอิง | ref referrer |
Interceptor เป็น ฟีเจอร์ที่ทรงพลังมาก ของ Saber ซึ่งช่วยให้คุณจัดการสิ่งต่าง ๆ ได้อย่างสะดวก เช่น การพิมพ์บันทึกการพัฒนา:
SaberGM:: get ( ' http://twosee.cn/ ' , [
' before ' => function ( Saber Request $ request ) {
$ uri = $ request -> getUri ();
echo " log: request $ uri now... n" ;
},
' after ' => function ( Saber Response $ response ) {
if ( $ response -> success ) {
echo " log: success! n" ;
} else {
echo " log: failed n" ;
}
echo " use { $ response -> time } s " ;
}
]);
// log : request http : // twosee . cn / now...
// log : success !
// use 0 . 52036285400391s
แม้แต่异常自定义处理函数
และ会话
การจัดการข้อยกเว้นแบบกำหนดเองก็ยังถูกนำมาใช้ผ่านตัวสกัดกั้น
อาจมี Interceptor ได้หลายตัว ซึ่งจะดำเนินการตามลำดับการลงทะเบียน และคุณสามารถ ตั้งชื่อ Interceptor ได้ คุณเพียงแต่ต้องล้อมมันด้วยอาร์เรย์และระบุค่าคีย์ หากคุณต้องการลบ Interceptor นี้ เพียงเขียนทับด้วย ค่าว่าง
[
' after ' => [
' interceptor_new ' => function (){},
' interceptor_old ' => null
]
]
Interceptors สามารถลงทะเบียนได้สี่วิธี (4 ฟังก์ชั่นการเรียกกลับ PHP):
callable: function (){}
string: ' function_name '
string: ' ClassName::method_name '
array: [ $ object , ' method_name ' ]
การใช้งานคุกกี้ เสร็จสมบูรณ์ในระดับเบราว์เซอร์ โดยอ้างถึงการใช้งานเบราว์เซอร์ Chrome โดยเฉพาะและปฏิบัติตามกฎที่เกี่ยวข้อง
คุกกี้คือชุดของคุกกี้ และคุกกี้แต่ละตัวมีคุณสมบัติดังต่อไปนี้:
name
, value
, expires
, path
, session
, secure
, httponly
, hostonly
และคลาส Cookies รองรับการแปลงไฟล์ได้หลากหลายรูปแบบ เช่น
foo=bar; foz=baz; apple=banana
Set-Cookie: logged_in=no; domain=.github.com; path=/; expires=Tue, 06 Apr 2038 00:00:00 -0000; secure; HttpOnly
['foo'=>'bar', 'foz'=>'baz']
รอให้โอนรูปแบบไปยังคลาส Cookie หรือคลาส Cookie ให้เป็นอนุกรมเป็นรูปแบบเหล่านี้
คุกกี้ยังรองรับการตรวจสอบชื่อโดเมนและการจำกัดเวลาโดยไม่สูญเสียข้อมูลใดๆ ตัวอย่างเช่น หากโดเมนคือ github.com
คุกกี้จะไม่ปรากฏใน help.github.com
เว้นแต่โดเมนจะไม่ใช่โฮสต์เท่านั้น ( .github.com
wildcard)
หากเป็นคุกกี้เซสชัน (ไม่มีเวลาหมดอายุและหมดอายุเมื่อปิดเบราว์เซอร์) คุณลักษณะที่หมดอายุจะถูกตั้งค่าเป็นเวลาปัจจุบัน และคุณสามารถตั้งเวลาที่ระบุผ่าน interceptor
การอ่านแอตทริบิวต์ดิบของคุกกี้ทำให้สามารถ คงอยู่ในฐานข้อมูล ได้อย่างง่ายดาย ซึ่งเหมาะมากสำหรับแอปพลิเคชันรวบรวมข้อมูลการเข้าสู่ระบบ
สำหรับรายละเอียดเพิ่มเติม โปรดดูเอกสารและตัวอย่างไลบรารี Swlib/Http
เซเบอร์ปฏิบัติตามกฎการแยก ธุรกิจออกจากข้อผิดพลาด เมื่อส่วนใดส่วนหนึ่งของคำขอล้มเหลว ข้อยกเว้นจะถูกส่งออกไปโดยค่าเริ่มต้น
สิ่งที่มีประสิทธิภาพคือการจัดการข้อยกเว้นของ Saber นั้นมีความหลากหลายและสมบูรณ์พอๆ กับการจัดการข้อยกเว้นดั้งเดิมของ PHP
เนมสเปซข้อยกเว้นอยู่ใน SwlibHttpException
ข้อยกเว้น | บทนำ | ฉาก |
---|---|---|
ขอข้อยกเว้น | คำขอล้มเหลว | ขอข้อผิดพลาดในการกำหนดค่า |
ConnectException | การเชื่อมต่อล้มเหลว | หากไม่มีการเชื่อมต่อเครือข่าย การสืบค้น DNS ล้มเหลว หมดเวลา ฯลฯ ค่าของ errno จะเท่ากับ Linux errno คุณสามารถใช้ swoole_strerror เพื่อแปลงรหัสข้อผิดพลาดเป็นข้อความแสดงข้อผิดพลาด |
TooManyRedirectsException | เกินจำนวนการเปลี่ยนเส้นทาง | จำนวนการเปลี่ยนเส้นทางเกินขีดจำกัดที่ตั้งไว้ และข้อยกเว้นที่ส่งออกจะพิมพ์ข้อมูลการติดตามการเปลี่ยนเส้นทาง |
ClientException | ข้อยกเว้นของลูกค้า | เซิร์ฟเวอร์ส่งคืนรหัสข้อผิดพลาด 4xx |
ข้อยกเว้นเซิร์ฟเวอร์ | ข้อยกเว้นของเซิร์ฟเวอร์ | เซิร์ฟเวอร์ส่งคืนรหัสข้อผิดพลาด 5xx |
BadResponseException | การตอบกลับการรับที่ไม่รู้จักล้มเหลว | เซิร์ฟเวอร์ไม่ตอบสนองหรือส่งคืนรหัสข้อผิดพลาดที่ไม่รู้จัก |
นอกเหนือจากวิธีการยกเว้นทั่วไปแล้ว คลาสข้อยกเว้น HTTP ทั้งหมดยังมีวิธีการดังต่อไปนี้:
วิธี | บทนำ |
---|---|
รับคำขอ | รับอินสแตนซ์คำขอ |
มีการตอบสนอง | ว่าจะได้รับคำตอบ. |
รับการตอบสนอง | รับอินสแตนซ์การตอบสนอง |
getResponseBodySummary | รับเนื้อหาสรุปของเนื้อหาการตอบกลับ |
try {
echo SaberGM:: get ( ' http://httpbin.org/redirect/10 ' );
} catch ( TooManyRedirectsException $ e ) {
var_dump ( $ e -> getCode ());
var_dump ( $ e -> getMessage ());
var_dump ( $ e -> hasResponse ());
echo $ e -> getRedirectsTrace ();
}
// int ( 302)
// string ( 28) "Too many redirects occurred ! "
// bool ( true )
#0 http : // httpbin . org / redirect/10
#1 http : // httpbin . org / relative - redirect/9
#2 http : // httpbin . org / relative - redirect/8
ในเวลาเดียวกัน Saber ยังรองรับการจัดการข้อยกเว้นด้วยวิธีที่อ่อนโยน เพื่อป้องกันไม่ให้ผู้ใช้ตกอยู่ในภาวะตื่นตระหนกในสภาพแวดล้อมเครือข่ายที่ไม่เสถียร และต้องพยายามห่อโค้ดในทุกขั้นตอน:
ตั้งค่าระดับรายงานข้อผิดพลาดซึ่งมี ผลใช้ทั่วโลก และ จะไม่มีผลกับอินสแตนซ์ที่สร้างขึ้น
// 启用所有异常但忽略重定向次数过多异常
SaberGM:: exceptionReport (
HttpExceptionMask:: E_ALL ^ HttpExceptionMask:: E_REDIRECT
);
ค่าต่อไปนี้ (ตัวเลขหรือสัญลักษณ์) ใช้เพื่อสร้างบิตมาสก์ที่ระบุข้อความแสดงข้อผิดพลาดที่จะรายงาน คุณสามารถใช้ตัวดำเนินการระดับบิตเพื่อรวมค่าเหล่านี้หรือเพื่อปกปิดข้อผิดพลาดบางประเภทได้ ธงและหน้ากาก
หน้ากาก | ค่า | บทนำ |
---|---|---|
E_NONE | 0 | ละเว้นข้อยกเว้นทั้งหมด |
E_คำขอ | 1 | สอดคล้องกับ RequestException |
E_CONNECT | 2 | สอดคล้องกับ RequestException |
E_REDIRECT | 4 | สอดคล้องกับ RequestException |
E_BAD_RESPONSE | 8 | สอดคล้องกับ BadRException |
E_CLIENT | 16 | สอดคล้องกับ ClientException |
อี_เซิร์ฟเวอร์ | 32 | สอดคล้องกับ ServerException |
อี_ออล | 63 | ข้อยกเว้นทั้งหมด |
ฟังก์ชันนี้สามารถจัดการข้อผิดพลาดที่สร้างขึ้นในคำขอ HTTP ด้วยวิธีของคุณเอง และคุณสามารถกำหนดข้อยกเว้นที่คุณต้องการตรวจจับ/ละเว้นได้อย่างอิสระมากขึ้น
หมายเหตุ: เว้นแต่ว่าฟังก์ชันจะส่งกลับ ค่า TRUE (หรือค่าจริงอื่นๆ) ข้อยกเว้นจะยังคงถูกส่งต่อไป แทนที่จะถูกจับโดยฟังก์ชันแบบกำหนดเอง
SaberGM:: exceptionHandle ( function ( Exception $ e ) {
echo get_class ( $ e ) . " is caught! " ;
return true ;
});
SaberGM:: get ( ' http://httpbin.org/redirect/10 ' );
//output : Swlib Http E xceptionTooManyRedirectsException is caught !
อัพโหลดไฟล์ | เว็บซ็อกเก็ต | โปรแกรมแยกวิเคราะห์อัตโนมัติ | ลองใหม่อัตโนมัติ | ดาวน์โหลดไฟล์ขนาดใหญ่ | แคช | ClientPool | สุ่มUA |
---|---|---|---|---|---|---|---|
4 (ลำดับความสำคัญสูง) | 3 | 2 | 1 | .5 | .5 | .5 | .175 |
เนื่องจากคุณประโยชน์หลักของ HTTP/2 คือการอนุญาตให้ส่งคำขอหลายรายการภายในการเชื่อมต่อเดียว ดังนั้น [เกือบ] จึงลบขีดจำกัดของจำนวนคำขอพร้อมกัน - และไม่มีขีดจำกัดดังกล่าวเมื่อพูดคุยกับแบ็กเอนด์ของคุณเอง ยิ่งไปกว่านั้น สิ่งต่างๆ อาจเกิดขึ้นด้วยซ้ำ จะแย่ลงเมื่อใช้ HTTP/2 กับแบ็กเอนด์ เนื่องจากมีการเชื่อมต่อ TCP เดียวแทนที่จะใช้หลายรายการ ดังนั้น Http2 จะไม่มีความสำคัญ (#ref)
เพิ่มไฟล์ต้นฉบับของโครงการนี้ไปยัง Include Path
ของ IDE
(หากติดตั้งโดยใช้ผู้แต่งเพลง คุณสามารถรวมโฟลเดอร์ผู้ขายทั้งหมดได้ และ PHPStorm จะรวมไว้โดยอัตโนมัติ)
การเขียนความคิดเห็นที่ดีทำให้ Sabre รองรับการแจ้งอัตโนมัติของ IDE ได้อย่างสมบูรณ์แบบ เพียงเขียนสัญลักษณ์ลูกศรหลังวัตถุเพื่อดูชื่อวิธีการของวัตถุทั้งหมดนั้นง่ายต่อการเข้าใจ โครงการตะลึง (ขอบคุณ) .
สำหรับพรอมต์ IDE ในคลาสที่เกี่ยวข้องกับ Swoole คุณต้องแนะนำ swoole-ide-helper ของ eaglewu (ผู้แต่งจะถูกติดตั้งตามค่าเริ่มต้นในสภาพแวดล้อม dev) อย่างไรก็ตาม โปรเจ็กต์นี้ได้รับการดูแลด้วยตนเองและยังไม่เสร็จสมบูรณ์ คุณยังสามารถใช้ swoot ได้อีกด้วย -ide-helper หรือ:
ผู้ช่วยไอดีอย่างเป็นทางการของ Swoole
ยินดีส่งประเด็นและประชาสัมพันธ์
เนื่องจากไม่สามารถใช้ coroutines (__call, __callStatic) ในเมธอดเวทย์มนตร์ได้ วิธีการในซอร์สโค้ดจึงถูกกำหนดด้วยตนเอง
เพื่อความสะดวกในการใช้งาน เราได้จัดเตรียมนามแฝงไว้สำหรับวิธีการร้องขอที่รองรับทั้งหมด
public static function psr( array $ options = []): Swlib Saber Request
public static function wait(): Swlib Saber
public static function request( array $ options = [])
public static function get (string $ uri , array $ options = [])
public static function delete (string $ uri , array $ options = [])
public static function head (string $ uri , array $ options = [])
public static function options (string $ uri , array $ options = [])
public static function post (string $ uri , $ data = null , array $ options = [])
public static function put (string $ uri , $ data = null , array $ options = [])
public static function patch (string $ uri , $ data = null , array $ options = [])
public static function download (string $ uri , string $ dir , int $ offset , array $ options = [])
public static function requests (array $ requests , array $ default_options = []): Swlib Saber ResponseMap
public static function list(array $ options , array $ default_options = []): Swlib Saber ResponseMap
public static function websocket (string $ uri )
public static function default (?array $ options = null ): array
public static function exceptionReport (?int $ level = null ): int
public static function exceptionHandle (callable $ handle ): void
public static function create( array $ options = []): self
public static function session( array $ options = []): self
public static function websocket( string $ uri ): WebSocket
public function request( array $ options )
public function get( string $ uri , array $ options = [])
public function delete( string $ uri , array $ options = [])
public function head( string $ uri , array $ options = [])
public function options( string $ uri , array $ options = [])
public function post( string $ uri , $ data = null , array $ options = [])
public function put( string $ uri , $ data = null , array $ options = [])
public function patch( string $ uri , $ data = null , array $ options = [])
public function download( string $ uri , string $ dir , int $ offset , array $ options = [])
public function requests( array $ requests , array $ default_options = []): ResponseMap
public function list( array $ options , array $ default_options = []): ResponseMap
public function upgrade(? string $ path = null ): WebSocket
public function psr( array $ options = []): Request
public function wait(): self
public function exceptionReport(? int $ level = null ): int
public function exceptionHandle( callable $ handle ): void
public static function getAliasMap(): array
public function setOptions( array $ options = [], ? Swlib Saber Request $ request = null ): self
public static function getDefaultOptions(): array
public static function setDefaultOptions( array $ options = [])
public function getExceptionReport(): int
public function setExceptionReport( int $ level ): self
public function isWaiting(): bool
public function getPool()
public function withPool( $ bool_or_max_size ): self
public function tryToRevertClientToPool( bool $ connect_failed = false )
public function getSSL(): int
public function withSSL( int $ mode = 2 ): self
public function getCAFile(): string
public function withCAFile( string $ ca_file = __DIR__ . ' /cacert.pem ' ): self
public function getSSLCertFile(): string
public function withSSLCertFile( string $ cert_file ): self
public function getSSLKeyFile(): string
public function withSSLKeyFile( string $ key_file ): self
public function withSSLVerifyPeer( bool $ verify_peer = false , ? string $ ssl_host_name = '' ): self
public function withSSLAllowSelfSigned( bool $ allow = true ): self
public function getSSLConf()
public function getKeepAlive()
public function withKeepAlive( bool $ enable ): self
public function withBasicAuth(? string $ username = null , ? string $ password = null ): self
public function withXHR( bool $ enable = true )
public function getProxy(): array
public function withProxy( string $ host , int $ port ): self
public function withSocks5( string $ host , int $ port , ? string $ username , ? string $ password ): self
public function withoutProxy(): self
public function getBindAddress(): ? string
public function withBindAddress( string $ address ): self
public function getBindPort(): ? int
public function withBindPort( int $ port ): self
public function getTimeout(): float
public function withTimeout( float $ timeout ): self
public function getRedirect(): int
public function getName()
public function withName( $ name ): self
public function withRedirect( int $ time ): self
public function isInQueue(): bool
public function withInQueue( bool $ enable ): self
public function getRetryTime(): int
public function withRetryTime( int $ time ): self
public function withAutoIconv( bool $ enable ): self
public function withExpectCharset( string $ source = ' auto ' , string $ target = ' utf-8 ' , bool $ use_mb = false ): self
public function withDownloadDir( string $ dir ): self
public function withDownloadOffset( int $ offset ): self
public function resetClient( $ client )
public function exec()
public function recv()
public function getRequestTarget(): string
public function withRequestTarget( $ requestTarget ): self
public function getMethod(): string
public function withMethod( $ method ): self
public function getUri(): Psr Http Message UriInterface
public function withUri(? Psr Http Message UriInterface $ uri , $ preserveHost = false ): self
public function getCookieParams(): array
public function getCookieParam( string $ name ): string
public function withCookieParam( string $ name , ? string $ value ): self
public function withCookieParams( array $ cookies ): self
public function getQueryParam( string $ name ): string
public function getQueryParams(): array
public function withQueryParam( string $ name , ? string $ value ): self
public function withQueryParams( array $ query ): self
public function getParsedBody(? string $ name = null )
public function withParsedBody( $ data ): self
public function getUploadedFile( string $ name ): Psr Http Message UploadedFileInterface
public function getUploadedFiles(): array
public function withUploadedFile( string $ name , ? Psr Http Message UploadedFileInterface $ uploadedFile ): self
public function withoutUploadedFile( string $ name ): self
public function withUploadedFiles( array $ uploadedFiles ): self
public function __toString()
public function getProtocolVersion(): string
public function withProtocolVersion( $ version ): self
public function hasHeader( $ name ): bool
public function getHeader( $ name ): array
public function getHeaderLine( $ name ): string
public function getHeaders( bool $ implode = false , bool $ ucwords = false ): array
public function getHeadersString( bool $ ucwords = true ): string
public function withHeader( $ raw_name , $ value ): self
public function withHeaders( array $ headers ): self
public function withAddedHeaders( array $ headers ): self
public function withAddedHeader( $ raw_name , $ value ): self
public function withoutHeader( $ name ): self
public function getBody(): Psr Http Message StreamInterface
public function withBody(? Psr Http Message StreamInterface $ body ): self
public function getCookies()
public function setCookie( array $ options ): self
public function unsetCookie( string $ name , string $ path = '' , string $ domain = '' ): self
public function withInterceptor( string $ name , array $ interceptor )
public function withAddedInterceptor( string $ name , array $ functions ): self
public function withoutInterceptor( string $ name ): self
public function callInterceptor( string $ name , $ arguments )
public function getSpecialMark( string $ name = ' default ' )
public function withSpecialMark( $ mark , string $ name = ' default ' ): self
public function isSuccess(): bool
public function getUri(): Psr Http Message UriInterface
public function getTime(): float
public function getRedirectHeaders(): array
public function getStatusCode()
public function withStatus( $ code , $ reasonPhrase = '' )
public function getReasonPhrase()
public function __toString()
public function getProtocolVersion(): string
public function withProtocolVersion( $ version ): self
public function hasHeader( $ name ): bool
public function getHeader( $ name ): array
public function getHeaderLine( $ name ): string
public function getHeaders( bool $ implode = false , bool $ ucwords = false ): array
public function getHeadersString( bool $ ucwords = true ): string
public function withHeader( $ raw_name , $ value ): self
public function withHeaders( array $ headers ): self
public function withAddedHeaders( array $ headers ): self
public function withAddedHeader( $ raw_name , $ value ): self
public function withoutHeader( $ name ): self
public function getBody(): Psr Http Message StreamInterface
public function withBody(? Psr Http Message StreamInterface $ body ): self
public function getCookies()
public function setCookie( array $ options ): self
public function unsetCookie( string $ name , string $ path = '' , string $ domain = '' ): self
public function getSpecialMark( string $ name = ' default ' )
public function withSpecialMark( $ mark , string $ name = ' default ' ): self
public function getParsedJsonArray( bool $ reParse = false ): array
public function getParsedJsonObject( bool $ reParse = false ): object
public function getParsedQueryArray( bool $ reParse = false ): array
public function getParsedXmlArray( bool $ reParse = false ): array
public function getParsedXmlObject( bool $ reParse = false ): SimpleXMLElement
public function getParsedDomObject( bool $ reParse = false ): DOMDocument
public function getDataRegexMatch( string $ regex , $ group = null , int $ fill_size )
public function getDataRegexMatches( string $ regex , int $ flag ): array
public function isExistInData( string $ needle , int $ offset )
public function enqueue( $ request )
public function getMaxConcurrency(): int
public function withMaxConcurrency( int $ num = - 1 ): self
public function recv(): Swlib Saber ResponseMap
public function withInterceptor( string $ name , array $ interceptor )
public function withAddedInterceptor( string $ name , array $ functions ): self
public function withoutInterceptor( string $ name ): self
public function callInterceptor( string $ name , $ arguments )
public $ time = 0.0 ;
public $ status_map = [];
public $ success_map = [];
public $ success_num = 0 ;
public $ error_num = 0 ;
public function offsetSet( $ index , $ response )
public function __toString()
public function withMock( bool $ ssl ): self
public function recv( float $ timeout = - 1 )
public function push( string $ data , int $ opcode = 1 , bool $ finish = true ): bool
public function close(): bool
public $ finish = true ;
public $ opcode = null ;
public $ data = null ;
public function getOpcodeDefinition()
public function getOpcode()
public function getData()
public function __toString()