Repository: pinpoint-apm/pinpoint-c-agent (language: python)

Issue:
PHP: bad License in package.xml
package.xml states 

`<license uri="http://www.php.net/license">PHP</license>`

LICENSE file is "Apache-2.0"

Please fix package.xml for consistency


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 92edefd7..b34c2991 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,9 +1,14 @@
 name: CI
 
-on: [pull_request, workflow_dispatch, push]
+on: 
+  pull_request:
+  workflow_dispatch:
+  push:
+    tags:
+      - "v*.*.*"
 
 env:
-  MODULE_PAK: pinpoint_php@${{ github.head_ref || github.ref_name }}
+  MODULE_PAK: pinpoint_php-${{ github.head_ref || github.ref_name }}
   
 jobs:
   cpp:
@@ -69,10 +74,12 @@ jobs:
             --log-file=valgrind-out.txt \
             ./bin/TestCommon
       - name: Archive docs
-        uses: actions/upload-artifact@v3
+        uses: actions/upload-artifact@v4
         with:
           name: valgrind-out
           path: common/build/valgrind-out.txt
+          retention-days: 5
+          if-no-files-found: error
 
   PHP:
     runs-on: ubuntu-latest
@@ -97,24 +104,142 @@ jobs:
         # if: always()
         run: ./docker-compose-linux-x86_64 -f "testapps/compose.yaml" down php-compatible
 
+  PHP-MacOS:
+    runs-on: macos-latest
+    needs: cpp
+    strategy:
+      matrix:
+        php-version: ["7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3"]
+        ts: ["ts","nts"]
+    env:
+      SKIP_MACOS_ACTION: true        
+    steps:
+      - uses: actions/checkout@v2
+        with:
+          submodules: "true"
+      - name: Setup PHP with PECL extension
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: ${{ matrix.php-versions }}
+        env:
+          phpts: ${{ matrix.ts }}
+      - name: build pinpoint_php
+        run:  phpize && ./configure && make 
+      - name: make test      
+        run: make test TESTS="--show-diff tests_macos"
+
+  PHP-Win-2019:
+    runs-on: windows-2019
+    needs: cpp-windows
+    strategy:
+      matrix:
+        php-versions: [ "7.4", "7.3", "7.2","7.1","8.0", "8.1", "8.2", "8.3"]
+        arch: [ "x86" ,"x64"]
+        ts: [ "ts", "nts" ]
+    env:
+      SKIP_WINDOWS_ACTION: true
+    steps:
+      - uses: actions/checkout@v2
+      - id: setup-php-sdk
+        uses: php/setup-php-sdk@v0.8
+        with:
+          version: ${{ matrix.php-versions }}
+          arch: ${{ matrix.arch }}
+          ts: ${{ matrix.ts }}
+      - uses: ilammy/msvc-dev-cmd@v1
+        with:
+          arch: ${{ matrix.arch }}
+          toolset: ${{steps.setup-php-sdk.outputs.toolset}}
+
+      - name: build pinpoint_php on windows
+        run: |
+          php -m
+          php -v
+          mkdir output
+          phpize
+          ./configure.bat --enable-pinpoint_php --enable-debug-pack --enable-object-out-dir=output --with-prefix=${{steps.setup-php-sdk.outputs.prefix}}
+          nmake
+
+      - name: test pinpoint_php on windows      
+        run: |
+          # from https://github.com/php/setup-php-sdk/issues/7
+          nmake test TESTS="--show-diff tests_win32"
+          echo "pinpoint_php_win32_pack_name=${{ env.MODULE_PAK }}-${{ matrix.php-versions }}-${{ matrix.ts }}-${{steps.setup-php-sdk.outputs.vs}}-${{ matrix.arch }}" | Out-File -FilePath $env:GITHUB_ENV -Append 
+
+      - name: package
+        run: |
+          mkdir _package_
+          if (Test-Path -Path output/Release/ -PathType Container) {
+              cp output/Release/php_pinpoint_php.dll _package_
+              cp output/Release/php_pinpoint_php.pdb _package_
+              cp output/Release/php_pinpoint_php.lib _package_
+          } 
+
+          if (Test-Path -Path output/Release_TS/ -PathType Container) {
+              cp output/Release_TS/php_pinpoint_php.dll _package_
+              cp output/Release_TS/php_pinpoint_php.pdb _package_
+              cp output/Release_TS/php_pinpoint_php.lib _package_
+          } 
+
+          cp NOTICE _package_
+          cp README.md _package_
+          cp CHANGES-PHP.md _package_
+          cp LICENSE _package_
+          Compress-Archive -Path _package_/*   ${{ env.pinpoint_php_win32_pack_name }}.zip 
+      - uses: actions/upload-artifact@v4
+        with:
+          name: ${{ env.pinpoint_php_win32_pack_name }}
+          path: ${{ env.pinpoint_php_win32_pack_name }}.zip 
+          retention-days: 5
+          if-no-files-found: error
+
+  PHP-Release-Win32-Package:
+    needs: [ PHP-Win-2019, pack_php_module]
+    runs-on: ubuntu-latest
+    if: startsWith(github.ref, 'refs/tags/')
+    steps:
+      - name: Download All Artifacts
+        uses: actions/download-artifact@v4
+        with:
+          path: pinpoint-artifact
+          pattern: pinpoint_php*
+          merge-multiple: true
+      - run: ls -R pinpoint-artifact
+
+      - name: Release php_package
+        id: rel_php_pak
+        uses: softprops/action-gh-release@v2
+        with:
+          files: pinpoint-artifact/*
+
   pack_php_module:
     runs-on: ubuntu-latest
     needs: PHP
     steps:
       - uses: actions/checkout@v2
-      - name: Package pinpoint_php
-        id: pack
-        run: |
-          tar -czf ${{ env.MODULE_PAK }} common/  src/PHP config.m4 tests LICENSE
-          md5=($(md5sum ${{ env.MODULE_PAK }} ))
-          PACK_NAME=${{ env.MODULE_PAK }}-${md5}-$(date '+%Y-%m-%d').tar.gz
-          mv ${{ env.MODULE_PAK }} $PACK_NAME
-          echo "PACK=$PACK_NAME" >> $GITHUB_OUTPUT
+      - name: Setup PHP without composer
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: '8.3'
+
+      - name: pecl package
+        run: pecl package
+
+      # - name: Package pinpoint_php
+      #   id: pack
+      #   run: |
+      #     tar -czf ${{ env.MODULE_PAK }} common/ config.m4 tests LICENSE pinpoint_php.cpp php_pinpoint_php.h
+      #     md5=($(md5sum ${{ env.MODULE_PAK }} ))
+      #     pinpoint_php_win32_pack_name=${{ env.MODULE_PAK }}-${md5}-$(date '+%Y-%m-%d').tar.gz
+      #     mv ${{ env.MODULE_PAK }} $pinpoint_php_win32_pack_name
+      #     echo "PACK=$pinpoint_php_win32_pack_name" >> $GITHUB_OUTPUT
 
-      - uses: actions/upload-artifact@v3
+      - uses: actions/upload-artifact@v4
         with:
-          name: ${{ env.MODULE_PAK }}
-          path: ${{ steps.pack.outputs.PACK }}
+          name: pinpoint_php.tgz
+          path: pinpoint_php*.tgz
+          retention-days: 5
+          if-no-files-found: error
 
   Python:
     strategy:
@@ -133,8 +258,8 @@ jobs:
           # ref https://github.com/pypa/setuptools/issues/3198
           pip install -e .
           python -m unittest discover -s src/PY/test
+
   python-plugins:
-    # timeout-minutes: 20
     needs: Python
     runs-on: ubuntu-latest
     steps:
@@ -153,17 +278,19 @@ jobs:
       - name: Stop containers
         # if: always()
         run: ./docker-compose-linux-x86_64 -f "testapps/compose.yaml" down python-plugins
+
   Collector-agent:
     strategy:
       matrix:
         go-version: [1.18.x]
-        os: [ubuntu-latest]
+        os: [ubuntu-latest,windows-latest,macos-latest]
     runs-on: ${{ matrix.os }}
     steps:
       - name: Install Go
         uses: actions/setup-go@v2
         with:
           go-version: ${{ matrix.go-version }}
+          
       - name: Checkout code
         uses: actions/checkout@v2
         with:
@@ -171,9 +298,12 @@ jobs:
 
       - name: Setup protoc
         uses: arduino/setup-protoc@v2.1.0
+        with:
+          repo-token: ${{ secrets.GITHUB_TOKEN }}
 
-      - run: |
+      - name: run unittest
+        run: |
           go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
           go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
-          export PATH="$PATH:$(go env GOPATH)/bin"
-          cd collector-agent && make && go test ./... -v
+          # export PATH="$PATH:$(go env GOPATH)/bin"
+          cd collector-agent && go mod tidy && go test ./... -v
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 811cc94c..8921ba83 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -17,7 +17,7 @@ jobs:
       - name: Package pinpoint_php
         id: pack
         run: |
-          tar -czf ${{ env.MODULE_PAK }} common/  src/PHP config.m4 tests LICENSE
+          tar -czf ${{ env.MODULE_PAK }} common/ pinpoint_php.cpp php_pinpoint_php.h config.m4 tests LICENSE
           md5=($(md5sum ${{ env.MODULE_PAK }} ))
           PACK_NAME=${{ env.MODULE_PAK }}-${md5}-$(date '+%Y-%m-%d').tar.gz
           mv ${{ env.MODULE_PAK }} $PACK_NAME
diff --git a/.gitignore b/.gitignore
index 6d9675c1..50e51cc3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -66,7 +66,7 @@ test.php
 .libs/
 .libs/
 aclocal.m4
-src/PHP/pinpoint_php.dep
+pinpoint_php.dep
 collector-agent/collector-agent
 .cache
 compile_commands.json
@@ -78,4 +78,10 @@ wheelhouse/
 .vs
 *.dep
 downloads
-testapps/java_call_app/target
\ No newline at end of file
+testapps/java_call_app/target
+x64
+x86
+output
+config.nice.bat
+configure.bat
+configure.js
\ No newline at end of file
diff --git a/src/PHP/CHANGES.md b/CHANGES-PHP.md
similarity index 73%
rename from src/PHP/CHANGES.md
rename to CHANGES-PHP.md
index 3e6fb8e0..354d17c8 100644
--- a/src/PHP/CHANGES.md
+++ b/CHANGES-PHP.md
@@ -1,3 +1,8 @@
+## 0.5.3 2024-07-31
+- build on win32
+- build on macos
+- support SendSpanTimeOutMs=-1
+
 ## 0.5.2 2024-05-30
 - add pinpoint_get_caller_arg
 
diff --git a/DOC/PHP/Readme-CN.md b/DOC/PHP/Readme-CN.md
index 59fdce8f..6bab2bcb 100644
--- a/DOC/PHP/Readme-CN.md
+++ b/DOC/PHP/Readme-CN.md
@@ -2,20 +2,24 @@
 
 ### 依赖组件
 
-Dependency|Version| More
----|----|----
-PHP| php `7+`|
-GCC| GCC `4.7+`| C++11 
-*inux|| `windows is on the way`
-pinpoint| `2.0+`|
-composer| | class can be automatic pinpoint-cut
-collector-agent| [installed ?](../collector-agent/readme.md)
+| Dependency          | Version                                     | More                                |
+| ------------------- | ------------------------------------------- | ----------------------------------- |
+| PHP                 | php `7+`                                    |
+| *inux/windows/macOs |                                             | windows is released                 |
+| pinpoint            | `2.0+`                                      |
+| composer            |                                             | class can be automatic pinpoint-cut |
+| collector-agent     | [installed ?](../collector-agent/readme.md) |
 
 ### 安装步骤
 
 1. 安装 `ext-pinpoint_php` 模块
 
-   curl -sL https://github.com/pinpoint-apm/pinpoint-c-agent/releases/download/v0.6.0/install_pinpoint_php.sh | sh
+     `pecl install pinpoint_php`
+     or 
+     `curl -sL https://github.com/pinpoint-apm/pinpoint-c-agent/releases/download/latest/install_pinpoint_php.sh | sh`
+
+     > On windows: download .dll from  https://pecl.php.net/package/pinpoint_php  or https://github.com/pinpoint-apm/pinpoint-c-agent/releases/latest
+
 
 2. 检查下你的配置文件 pinpoint_php.ini
          
diff --git a/DOC/PHP/Readme-KR.md b/DOC/PHP/Readme-KR.md
index 10c98ee4..1fad0ca0 100644
--- a/DOC/PHP/Readme-KR.md
+++ b/DOC/PHP/Readme-KR.md
@@ -2,19 +2,23 @@
 
 ### 요구
 
-디펜던시 | 버전 | 부가
----|----|----
-PHP| php `7+`|
-GCC| GCC `4.7+`| C++11 
-*inux|| `windows is on the way`
-pinpoint| `2.0+`|
-composer| | class can be automatic pinpoint-cut
-collector-agent| [installed ?](../collector-agent/readme.md)
+| 디펜던시            | 버전                                        | 부가                                |
+| ------------------- | ------------------------------------------- | ----------------------------------- |
+| PHP                 | php `7+`                                    |
+| *inux/windows/macOs |                                             | windows is released                 |
+| pinpoint            | `2.0+`                                      |
+| composer            |                                             | class can be automatic pinpoint-cut |
+| collector-agent     | [installed ?](../collector-agent/readme.md) |
 
 ### 설치 스텝
 
 1. `ext-pinpoint_php` 모듈 설치 
-    curl -sL https://github.com/pinpoint-apm/pinpoint-c-agent/releases/download/v0.6.0/install_pinpoint_php.sh | sh
+   
+     `pecl install pinpoint_php`
+     or 
+     `curl -sL https://github.com/pinpoint-apm/pinpoint-c-agent/releases/download/latest/install_pinpoint_php.sh | sh`
+
+     > On windows: download .dll from  https://pecl.php.net/package/pinpoint_php  or https://github.com/pinpoint-apm/pinpoint-c-agent/releases/latest
 
 2. pinpoint_php.ini 설정 파일 확인
      ```ini
diff --git a/DOC/PHP/Readme.md b/DOC/PHP/Readme.md
index 44c7e117..14a8916c 100644
--- a/DOC/PHP/Readme.md
+++ b/DOC/PHP/Readme.md
@@ -6,21 +6,24 @@
 
 ### Requirement
 
-Dependency|Version| More
----|----|----
-PHP| php `7+`|
-GCC| GCC `4.7+`| C++11 
-*inux|| `windows is on the way`
-pinpoint| `2.0+`|
-composer| | class can be automatic pinpoint-cut
-collector-agent| [installed ?](../collector-agent/readme.md)
+| Dependency          | Version                                     | More                                |
+| ------------------- | ------------------------------------------- | ----------------------------------- |
+| PHP                 | php `7+`                                    |
+| *inux/windows/macOs |                                             | windows is released                 |
+| pinpoint            | `2.0+`                                      |
+| composer            |                                             | class can be automatic pinpoint-cut |
+| collector-agent     | [installed ?](../collector-agent/readme.md) |
 
 ### Installation
 
 #### Steps
 1. Install `ext-pinpoint_php`
 
-   curl -sL https://github.com/pinpoint-apm/pinpoint-c-agent/releases/download/v0.6.0/install_pinpoint_php.sh | sh
+     `pecl install pinpoint_php`
+     or 
+     `curl -sL https://github.com/pinpoint-apm/pinpoint-c-agent/releases/download/latest/install_pinpoint_php.sh | sh`
+
+     > On windows: download .dll from  https://pecl.php.net/package/pinpoint_php  or https://github.com/pinpoint-apm/pinpoint-c-agent/releases/latest
 
 2. Check your pinpoint_php.ini is right
          
diff --git a/common/CHANGES.md b/common/CHANGES.md
index 1f9ef3fd..c89ce6e4 100644
--- a/common/CHANGES.md
+++ b/common/CHANGES.md
@@ -1,3 +1,9 @@
+## v0.5.3 2024-07-30
+- support unittest in macos
+
+## v0.5.2 2024-07-26
+- fix `tick++`
+
 ## v0.5.1 2024-05-07
 - fix logging bug
 - add EXP_V2 protocol 2024-04-30
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 28278906..ce5c5088 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.13)
-project(pinpoint VERSION 0.5.1 DESCRIPTION  "pinpoint common library")
+project(pinpoint VERSION 0.5.3 DESCRIPTION  "pinpoint common library")
 
 set(CMAKE_CXX_STANDARD 11)
 
diff --git a/common/include/common.h b/common/include/common.h
index dd71d558..15b726bc 100644
--- a/common/include/common.h
+++ b/common/include/common.h
@@ -73,7 +73,7 @@ static const NodeID E_ROOT_NODE = 0;
 static const E_NODE_LOC E_LOC_CURRENT = 0x0;
 static const E_NODE_LOC E_LOC_ROOT = 0x1;
 
-#define PINPOINT_C_AGENT_API_VERSION "0.5.0"
+#define PINPOINT_C_AGENT_API_VERSION "0.5.3"
 
 /**
  * @brief change logs
diff --git a/common/src/Cache/State.cpp b/common/src/Cache/State.cpp
index dbeab245..83d28023 100644
--- a/common/src/Cache/State.cpp
+++ b/common/src/Cache/State.cpp
@@ -17,6 +17,8 @@
 #include "State.h"
 #include "common.h"
 #include "header.h"
+#include <inttypes.h> /* For PRIu64 */
+
 namespace PP {
 ProcessState::ProcessState(int64_t trace_limit)
     : starttime_(get_unix_time_ms()), trace_limit_(trace_limit) {}
@@ -30,23 +32,24 @@ void ProcessState::SetStartTime(uint64_t start_time) {
 }
 
 bool ProcessState::CheckTraceLimit(int64_t timestamp) {
-  time_t now = (timestamp != -1) ? (timestamp) : (std::time(NULL));
+  std::time_t now = (timestamp != -1) ? (static_cast<std::time_t>(timestamp)) : (std::time(NULL));
   if (trace_limit_ == -1) {
     return false;
   } else if (trace_limit_ == 0) {
-    goto BLOCK;
+    goto LIMITED;
   }
 
   if (timestamp_ != now) {
     timestamp_ = now;
     tick_ = 0;
-  } else if (++tick_ >= trace_limit_) {
-    goto BLOCK;
+  } else if (tick_ >= trace_limit_) {
+    goto LIMITED;
   }
+  tick_++;
   return false;
-BLOCK:
-  pp_trace("This span dropped. max_trace_limit:%ld current_tick:%lld onLine:%d", trace_limit_,
-           tick_, this->IsReady() ? (1) : (0));
+LIMITED:
+  pp_trace("This span dropped. max_trace_limit:%" PRIu64 " current_tick:%" PRIu64 " onLine:%d",
+           trace_limit_, tick_.load(), (this->IsReady() ? (1) : (0)));
   return true;
 }
 
diff --git a/common/src/Cache/State.h b/common/src/Cache/State.h
index 6ede83ac..200bc73b 100644
--- a/common/src/Cache/State.h
+++ b/common/src/Cache/State.h
@@ -45,11 +45,11 @@ class ProcessState : public State {
   virtual ~ProcessState() = default;
 
 private:
-  int64_t tick_ = {0};
+  std::atomic<int64_t> tick_ = {0};
   std::time_t timestamp_ = {0};
   // default is the unix time in ms
   uint64_t starttime_;
-  int64_t trace_limit_;
+  const int64_t trace_limit_;
   std::atomic<std::int64_t> uuid_ = {0};
   bool ready_ = {false};
 };
diff --git a/common/src/NodePool/TraceNode.cpp b/common/src/NodePool/TraceNode.cpp
index b085e627..50317f7d 100644
--- a/common/src/NodePool/TraceNode.cpp
+++ b/common/src/NodePool/TraceNode.cpp
@@ -102,8 +102,8 @@ void TraceNode::parseOpt(std::string key, std::string value) {
   if (key == "TraceMinTimeMs") {
     int64_t min = std::stoll(value);
     auto cb = [=]() -> bool {
-      pp_trace("checkOpt:  [%d] TraceMinTimeMs:%ld cumulative_time:%lu", this->id_, min,
-               this->cumulative_time);
+      pp_trace("checkOpt:  [%d] TraceMinTimeMs:%" PRIu64 " cumulative_time:%" PRIu64 "", this->id_,
+               min, this->cumulative_time);
       if ((int64_t)this->cumulative_time >= min)
         return true;
       return false;
diff --git a/common/src/NodePool/TraceNode.h b/common/src/NodePool/TraceNode.h
index 4646440c..ce68b040 100644
--- a/common/src/NodePool/TraceNode.h
+++ b/common/src/NodePool/TraceNode.h
@@ -251,7 +251,7 @@ class TraceNode {
                  "root_start_time:%" PRIu64 ",set_exp_:%d \n"
                  "ref_count_:%d \n"
                  "_value:%s \n"
-                 "context_ size:%" PRIu64 ",_endTraceCallback:%" PRIu64 " \n",
+                 "context_ size:%zu,_endTraceCallback:%zu \n ",
                  (int)this->sibling_id_, (int)this->last_child_id_, (int)this->parent_id_,
                  (int)this->root_id_, (int)this->id_, this->start_time, this->fetal_error_time,
                  this->limit, this->cumulative_time, this->root_start_time, this->set_exp_,
@@ -288,6 +288,7 @@ class WrapperTraceNodePtr {
   WrapperTraceNodePtr() = delete;
   WrapperTraceNodePtr(const WrapperTraceNodePtr& other) = delete;
   WrapperTraceNodePtr(WrapperTraceNodePtr& other) = delete;
+
   WrapperTraceNodePtr(WrapperTraceNodePtr&& other) : traceNode_(other.traceNode_) {
     traceNode_.addRef();
   }
diff --git a/common/src/common.cpp b/common/src/common.cpp
index 04666149..a2fddd03 100644
--- a/common/src/common.cpp
+++ b/common/src/common.cpp
@@ -78,6 +78,8 @@ class Agent {
     }
     if (span_timeout > 0) {
       trans->SyncSendAll(span_timeout);
+    } else if (span_timeout < 0) {
+      pp_trace("[unittest] current span was dropped");
     } else {
       trans->PoolEventOnce(0);
     }
@@ -167,7 +169,8 @@ class Agent {
         } else if (w_trace->limit & E_TRACE_BLOCK) {
           pp_trace("current [%d] span dropped,due to TRACE_BLOCK", w_trace->getId());
         } else {
-          pp_trace("current [%d] span dropped,due to limit=%ld", w_trace->getId(), w_trace->limit);
+          pp_trace("current [%d] span dropped,due to limit=%" PRIu64 "", w_trace->getId(),
+                   w_trace->limit);
         }
       } else {
         w_trace->EndTimer();
diff --git a/composer.json b/composer.json
new file mode 100644
index 00000000..a28350b7
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,15 @@
+{
+    "name": "pinpoint_php",
+    "version": "0.5.2",
+    "type": "extension",
+    "license": [
+        "Apache License 2.0"
+    ],
+    "authors": [
+        {
+            "name": "Jason Mile",
+            "email": "liu_ming_yi@outlook.com"
+        }
+    ],
+    "description": "PHP extension for pinpoint-apm"
+}
\ No newline at end of file
diff --git a/config.m4 b/config.m4
index 2dbfbff9..ef46369c 100644
--- a/config.m4
+++ b/config.m4
@@ -11,14 +11,7 @@ if test "$PHP_PINPOINT_PHP" != "no"; then
   
   PHP_REQUIRE_CXX()
   PHP_SUBST(PINPOINT_PHP_SHARED_LIBADD)
-  PHP_ADD_LIBRARY(stdc++, 1, PINPOINT_PHP_SHARED_LIBADD)
-  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/common/include)
-  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/common/jsoncpp/include)
-  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/common/jsoncpp/include)
-  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/common/src)
-  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/src/PHP)
-  AC_DEFINE(HAVE_PINPOINT_PHP, 1, [Whether you have pinpoint])
-
+  
   # echo "------Build common libraries------------"
   # mkdir -p PHP_EXT_SRCDIR()/build
   # cd build 
@@ -28,7 +21,7 @@ if test "$PHP_PINPOINT_PHP" != "no"; then
   # PINPOINT_COMMON_LIB=PHP_EXT_SRCDIR()/build/lib
   # echo "----------------------------------------"
 
-  EXTRA_PHP_SRCS="src/PHP/pinpoint_php.cpp"
+  EXTRA_PHP_SRCS="pinpoint_php.cpp"
 
   PINPOINT_SRCS="$EXTRA_PHP_SRCS \
     common/src/common.cpp \
@@ -44,10 +37,20 @@ if test "$PHP_PINPOINT_PHP" != "no"; then
     common/jsoncpp/lib_json/json_value.cpp \
     common/jsoncpp/lib_json/json_reader.cpp \
   "
-
-
-  PINPOINT_PHP_SHARED_LIBADD="$PINPOINT_PHP_SHARED_LIBADD -lrt"
+  if  [[ "$OSTYPE" == "linux-gnu"* ]]; then
+    PINPOINT_PHP_SHARED_LIBADD="$PINPOINT_PHP_SHARED_LIBADD -lrt"
+  fi
   
   PHP_NEW_EXTENSION(pinpoint_php,$PINPOINT_SRCS, $ext_shared)
-  PHP_ADD_BUILD_DIR($ext_builddir/src/PHP)
-fi
\ No newline at end of file
+  PHP_ADD_LIBRARY(stdc++, 1, PINPOINT_PHP_SHARED_LIBADD)
+  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/common/include)
+  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/common/jsoncpp/include)
+  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/common/jsoncpp/include)
+  PHP_ADD_INCLUDE(PHP_EXT_SRCDIR()/common/src)
+  AC_DEFINE(HAVE_PINPOINT_PHP, 1, [Whether you have pinpoint])
+  PHP_ADD_BUILD_DIR(common/src/)
+  PHP_ADD_BUILD_DIR(common/src/NodePool/)
+  PHP_ADD_BUILD_DIR(common/src/ConnectionPool/)
+  PHP_ADD_BUILD_DIR(common/src/Cache/)
+  PHP_ADD_BUILD_DIR(common/jsoncpp/lib_json/)
+fi
diff --git a/config.w32 b/config.w32
new file mode 100644
index 00000000..9436917c
--- /dev/null
+++ b/config.w32
@@ -0,0 +1,35 @@
+// vim: ft=javascript:
+
+ARG_ENABLE("pinpoint_php", "whether to enable redis support", "no");
+
+
+if (PHP_PINPOINT_PHP != "no") {
+
+	// EXTENSION("pinpoint_php", "pinpoint_php.cpp", PHP_PINPOINT_PHP_SHARED,'-Icommon/jsoncpp/include -Icommon/include -Icommon/src  /EHsc /DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
+	EXTENSION("pinpoint_php", "pinpoint_php.cpp", PHP_PINPOINT_PHP_SHARED,'-Icommon/jsoncpp/include -Icommon/include -Icommon/src  /EHsc');
+	
+	ADD_SOURCES("common/src/", "\
+			common.cpp \
+			Logging.cpp \
+			", "pinpoint_php");
+	
+	ADD_SOURCES("common/src/NodePool", "\
+			TraceNode.cpp \
+			PoolManager.cpp \
+			", "pinpoint_php");	
+	
+	ADD_SOURCES("common/src/ConnectionPool", "\
+			TransLayer.cpp \
+			", "pinpoint_php");	
+	
+	ADD_SOURCES("common/src/Cache", "\
+			State.cpp \
+			Chunk.cpp \
+		","pinpoint_php")
+	
+	ADD_SOURCES( "common/jsoncpp/lib_json", "\
+			json_writer.cpp \
+			json_value.cpp \
+			json_reader.cpp\
+			", "pinpoint_php");
+}
diff --git a/package.xml b/package.xml
new file mode 100644
index 00000000..1d4c6602
--- /dev/null
+++ b/package.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+<package packagerversion="1.4.11" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0"
+  xmlns:tasks="http://pear.php.net/dtd/tasks-1.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd
+                      http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
+  <name>pinpoint_php</name>
+  <channel>pecl.php.net</channel>
+  <summary>PHP extension for pinpoint-apm</summary>
+  <description>
+    This extension provides an API pinpoint-apm and built-in function auto-injection
+  </description>
+  <lead>
+    <name>Jason Mile</name>
+    <user>eeliu</user>
+    <email>liu_ming_yi@outlook.com</email>
+    <active>yes</active>
+  </lead>
+  <lead>
+    <name>dl_cd_pinpoint</name>
+    <user>dl_cd_pinpoint</user>
+    <email>dl_cd_pinpoint@navercorp.com</email>
+    <active>yes</active>
+  </lead>
+  <date>2024-08-07</date>
+  <version>
+    <release>0.5.3</release>
+    <api>0.5.3</api>
+  </version>
+  <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+  </stability>
+  <license uri="https://www.apache.org/licenses/LICENSE-2.0">Apache License 2.0</license>
+  <notes>
+    ## 0.5.3 2024-07-31
+    - build on win32
+    - build on macos
+    - support SendSpanTimeOutMs=-1
+  </notes>
+  <contents>
+    <dir name="/">
+      <file role='doc' name='LICENSE' />
+      <file role='doc' name='CHANGES-PHP.md' />
+      <file role='doc' name='README.md' />
+      <file role='src' name='pinpoint_php.cpp' />
+      <file role='src' name='php_pinpoint_php.h' />
+      <file role='src' name='config.m4' />
+      <file role='src' name='config.w32' />
+      <dir name='common'>
+        <file role='doc' name='CHANGES.md' />
+        <file role='doc' name='readme.md' />
+        <dir name='include'>
+          <file role='src' name='common.h' />
+        </dir>
+        <dir name='jsoncpp'>
+          <dir name='include\json'>
+            <file role='src' name='allocator.h' />
+            <file role='src' name='assertions.h' />
+            <file role='src' name='config.h' />
+            <file role='src' name='forwards.h' />
+            <file role='src' name='json_features.h' />
+            <file role='src' name='json.h' />
+            <file role='src' name='reader.h' />
+            <file role='src' name='value.h' />
+            <file role='src' name='version.h' />
+            <file role='src' name='writer.h' />
+          </dir>
+          <dir name='lib_json'>
+            <file role='src' name='json_reader.cpp' />
+            <file role='src' name='json_tool.h' />
+            <file role='src' name='json_value.cpp' />
+            <file role='src' name='json_valueiterator.inl' />
+            <file role='src' name='json_writer.cpp' />
+          </dir>
+        </dir>
+        <dir name='src'>
+          <file role='src' name='common.cpp' />
+          <file role='src' name='header.h' />
+          <file role='src' name='Logging.cpp' />
+          <dir name='NodePool'>
+            <file role='src' name='PoolManager.cpp' />
+            <file role='src' name='PoolManager.h' />
+            <file role='src' name='TraceNode.cpp' />
+            <file role='src' name='TraceNode.h' />
+          </dir>
+          <dir name='Context'>
+            <file role='src' name='ContextType.h' />
+          </dir>
+          <dir name='ConnectionPool'>
+            <file role='src' name='sockets.h' />
+            <file role='src' name='TransLayer.h' />
+            <file role='src' name='TransLayer.cpp' />
+            <file role='src' name='SpanConnectionPool.h' />
+          </dir>
+          <dir name='Cache'>
+            <file role='src' name='Chunk.h' />
+            <file role='src' name='Chunk.cpp' />
+            <file role='src' name='State.h' />
+            <file role='src' name='State.cpp' />
+            <file role='src' name='NodeTreeWriter.h' />
+          </dir>
+        </dir>
+      </dir>
+    </dir>
+  </contents>
+  <dependencies>
+    <required>
+      <php>
+        <min>7.1.0</min>
+      </php>
+      <pearinstaller>
+        <min>1.4.0b1</min>
+      </pearinstaller>
+    </required>
+  </dependencies>
+  <providesextension>pinpoint_php</providesextension>
+  <extsrcrelease>
+  </extsrcrelease>
+  <changelog>
+    <release>
+      <stability>
+        <release>alpha</release>
+        <api>alpha</api>
+      </stability>
+      <version>
+        <release>0.5.3</release>
+        <api>0.5.3</api>
+      </version>
+      <date>2024-08-07</date>
+      <notes>
+        ## What's Changed
+        ## 0.5.3 2024-07-31
+        - build on win32
+        - build on macos
+        - support SendSpanTimeOutMs=-1
+      </notes>
+    </release>
+    <release>
+      <stability>
+        <release>stable</release>
+        <api>stable</api>
+      </stability>
+      <version>
+        <release>0.5.2</release>
+        <api>0.5.2</api>
+      </version>
+      <date>2024-07-29</date>
+      <notes>
+        ## What's Changed
+        - add pinpoint_get_caller_arg
+
+        **Full Changelog**: https://github.com/pinpoint-apm/pinpoint-c-agent/compare/v0.5.0...v0.6.0
+      </notes>
+    </release>
+
+  </changelog>
+</package>
\ No newline at end of file
diff --git a/src/PHP/php_pinpoint_php.h b/php_pinpoint_php.h
similarity index 96%
rename from src/PHP/php_pinpoint_php.h
rename to php_pinpoint_php.h
index 1330b19f..facb8802 100644
--- a/src/PHP/php_pinpoint_php.h
+++ b/php_pinpoint_php.h
@@ -16,8 +16,12 @@
 #ifndef PHP_PINPOINT_PHP_H
 #define PHP_PINPOINT_PHP_H
 
-#include "config.h"
 #include "zend_types.h"
+#ifdef __cplusplus
+
+extern "C" {
+#endif // __cplusplus
+
 extern zend_module_entry pinpoint_php_module_entry;
 #define phpext_pinpoint_php_ptr &pinpoint_php_module_entry
 
@@ -99,4 +103,9 @@ PHP_MSHUTDOWN_FUNCTION(pinpoint_php);
 PHP_RINIT_FUNCTION(pinpoint_php);
 PHP_RSHUTDOWN_FUNCTION(pinpoint_php);
 PHP_MINFO_FUNCTION(pinpoint_php);
+
+#ifdef __cplusplus
+} // extern C
+#endif // __cplusplus
+
 #endif /* PHP_PINPOINT_PHP_H */
diff --git a/src/PHP/pinpoint_php.cpp b/pinpoint_php.cpp
similarity index 95%
rename from src/PHP/pinpoint_php.cpp
rename to pinpoint_php.cpp
index 6730e802..0e1d8392 100644
--- a/src/PHP/pinpoint_php.cpp
+++ b/pinpoint_php.cpp
@@ -32,27 +32,28 @@
 */
 
 /* $Id$ */
-
-#include "zend_API.h"
-#include "zend_string.h"
-#include "zend_types.h"
+// clang-format off
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <iostream>
+#include <string>
 #include <cassert>
 #include <cstddef>
 #include <cstdint>
 #include <stdio.h>
-#include <strings.h>
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <cinttypes>
 
-// clang-format off
+#include "zend_API.h"
+#include "zend_string.h"
+#include "zend_types.h"
 #include "php.h"
 #include "php_ini.h"
 #include "ext/standard/info.h"
 
 #include "common.h"
 #include "php_pinpoint_php.h"
-#include <string>
+
 // clang-format on
 #ifdef COMPILE_DL_PINPOINT_PHP
 #ifdef ZTS
@@ -194,7 +195,8 @@ void (*old_error_cb)(int type, const char *error_filename,
                      const uint32_t error_lineno, zend_string *message);
 #else
 void (*old_error_cb)(int type, const char *error_filename,
-                     const uint error_lineno, const char *format, va_list args);
+                     const uint32_t error_lineno, const char *format,
+                     va_list args);
 #endif
 
 #define safe_free(x)                                                           \
@@ -204,12 +206,12 @@ void (*old_error_cb)(int type, const char *error_filename,
   }
 
 PHP_FUNCTION(_pinpoint_drop_trace) {
-  long _id = -1;
   NodeID id = E_ROOT_NODE, cur_id = E_ROOT_NODE;
 #if PHP_VERSION_ID < 70000
-
+  size_t _id = -1;
   zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &_id);
 #else
+  zend_long _id = -1;
   zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &_id);
 #endif
   if (_id == -1) {
@@ -233,13 +235,13 @@ PHP_FUNCTION(pinpoint_get_this) {
 }
 
 PHP_FUNCTION(_pinpoint_set_context) {
-  long _id = -1;
+
   std::string key;
   zval *zvalue;
 #if PHP_VERSION_ID < 70000
   char *zkey = NULL;
   int zkey_len;
-
+  size_t _id = -1;
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &zkey, &zkey_len,
                             &zvalue, &_id) == FAILURE) {
     zend_error(E_ERROR, "key/value required");
@@ -248,6 +250,7 @@ PHP_FUNCTION(_pinpoint_set_context) {
   key = std::string(zkey, zkey_len);
 
 #else
+  zend_long _id = -1;
   zend_string *zkey;
   if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &zkey, &zvalue, &_id) ==
       FAILURE) {
@@ -316,12 +319,14 @@ PHP_FUNCTION(pinpoint_get_caller_arg) {
 
   if ((zend_ulong)requested_offset >= arg_count) {
     zend_error(E_WARNING,
-               "pinpoint_get_caller_arg():  Argument " ZEND_LONG_FMT
-               " not passed to function",
+               "pinpoint_get_caller_arg():  Argument "
+               "%" PRId64 " not passed to function",
                requested_offset);
     RETURN_FALSE;
   }
 
+  // ZEND_LONG_FMT
+
   first_extra_arg = ex->func->op_array.num_args;
   if ((zend_ulong)requested_offset >= first_extra_arg &&
       (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg)) {
@@ -343,12 +348,12 @@ PHP_FUNCTION(pinpoint_get_caller_arg) {
 }
 
 PHP_FUNCTION(_pinpoint_get_context) {
-  long _id = -1;
+
   std::string key;
 #if PHP_VERSION_ID < 70000
+  long _id = -1;
   char *zkey = NULL;
-  int zkey_len;
-
+  size_t zkey_len;
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &zkey, &zkey_len,
                             &_id) == FAILURE) {
     zend_error(E_ERROR, "key/value required");
@@ -358,6 +363,7 @@ PHP_FUNCTION(_pinpoint_get_context) {
 
 #else
   zend_string *zkey;
+  zend_long _id = -1;
   if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &zkey, &_id) == FAILURE) {
     zend_error(E_ERROR, "key/value required");
     return;
@@ -381,14 +387,17 @@ PHP_FUNCTION(_pinpoint_get_context) {
   }
 }
 
-PHP_FUNCTION(_pinpoint_start_time) { RETURN_LONG(pinpoint_start_time()); }
+PHP_FUNCTION(_pinpoint_start_time) {
+  RETURN_DOUBLE(static_cast<double>(pinpoint_start_time()));
+}
 
 PHP_FUNCTION(_pinpoint_start_trace) {
-  long _id = -1;
   NodeID id = E_ROOT_NODE, cur_id = E_ROOT_NODE;
 #if PHP_VERSION_ID < 70000
+  long _id = -1;
   zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &_id);
 #else
+  zend_long _id = -1;
   zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &_id);
 #endif
   if (_id == -1) {
@@ -416,8 +425,9 @@ void apm_error_cb(int type, const char *_error_filename,
   const char *error_filename = _error_filename;
 #else
 
-void apm_error_cb(int type, const char *error_filename, const uint error_lineno,
-                  const char *format, va_list args) {
+void apm_error_cb(int type, const char *error_filename,
+                  const uint32_t error_lineno, const char *format,
+                  va_list args) {
   char *msg;
   va_list args_copy;
 #if PHP_VERSION_ID < 80000
@@ -452,13 +462,13 @@ void apm_error_cb(int type, const char *error_filename, const uint error_lineno,
 }
 
 PHP_FUNCTION(_pinpoint_end_trace) {
-  long _id = -1;
   NodeID id = E_ROOT_NODE, cur_id = E_ROOT_NODE;
 
 #if PHP_VERSION_ID < 70000
-
+  long _id = -1;
   zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &_id);
 #else
+  zend_long _id = -1;
   zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &_id);
 #endif
   if (_id == -1) {
@@ -478,12 +488,12 @@ PHP_FUNCTION(pinpoint_status) { show_status(); }
 PHP_FUNCTION(_pinpoint_add_clue) {
   std::string key;
   std::string value;
-  long _id = -1;
-  long _flag = E_LOC_CURRENT;
+
 #if PHP_VERSION_ID < 70000
   char *zkey = NULL, *zvalue = NULL;
   int zkey_len, value_len;
-
+  long _id = -1;
+  long _flag = E_LOC_CURRENT;
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &zkey,
                             &zkey_len, &zvalue, &value_len, &_id,
                             &_flag) == FAILURE) {
@@ -494,8 +504,10 @@ PHP_FUNCTION(_pinpoint_add_clue) {
   value = std::string(zvalue, value_len);
 
 #else
-  zend_string *zkey;
-  zend_string *zvalue;
+  zend_string *zkey = nullptr;
+  zend_string *zvalue = nullptr;
+  zend_long _id = -1;
+  zend_long _flag = E_LOC_CURRENT;
   if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|ll", &zkey, &zvalue, &_id,
                             &_flag) == FAILURE) {
     zend_error(E_ERROR, "pinpoint_add_clue() expects (int, string).");
@@ -508,17 +520,19 @@ PHP_FUNCTION(_pinpoint_add_clue) {
   pinpoint_add_clue(Id, key.c_str(), value.c_str(), (E_NODE_LOC)_flag);
 }
 
-PHP_FUNCTION(_pinpoint_unique_id) { RETURN_LONG(generate_unique_id()); }
+PHP_FUNCTION(_pinpoint_unique_id) {
+  RETURN_DOUBLE(static_cast<double>(generate_unique_id()));
+}
 
 PHP_FUNCTION(_pinpoint_mark_as_error) {
   std::string msg;
   std::string fileName;
-  long _lineno = 0;
-  long _id = -1;
+
 #if PHP_VERSION_ID < 70000
   char *zkey = NULL, *zvalue = NULL;
   int zkey_len, value_len;
-
+  long _lineno = 0;
+  long _id = -1;
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &zkey,
                             &zkey_len, &zvalue, &value_len, &_lineno,
                             &_id) == FAILURE) {
@@ -531,6 +545,8 @@ PHP_FUNCTION(_pinpoint_mark_as_error) {
 #else
   zend_string *zkey;
   zend_string *zvalue;
+  zend_long _lineno = 0;
+  zend_long _id = -1;
   if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|ll", &zkey, &zvalue, &_lineno,
                             &_id) == FAILURE) {
     zend_error(E_ERROR,
@@ -547,11 +563,11 @@ PHP_FUNCTION(_pinpoint_mark_as_error) {
 PHP_FUNCTION(_pinpoint_add_clues) {
   std::string key;
   std::string value;
+#if PHP_VERSION_ID < 70000
   long _id = -1;
   long _flag = E_LOC_CURRENT;
-#if PHP_VERSION_ID < 70000
   char *zkey = NULL, *zvalue = NULL;
-  int zkey_len, value_len;
+  size_t zkey_len, value_len;
 
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &zkey,
                             &zkey_len, &zvalue, &value_len, &_id,
@@ -564,8 +580,11 @@ PHP_FUNCTION(_pinpoint_add_clues) {
 #else
   zend_string *zkey;
   zend_string *zvalue;
-  if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|ll", &zkey, &zvalue, &_id,
-                            &_flag) == FAILURE) {
+  zend_long _id = -1;
+  zend_long _flag = E_LOC_CURRENT;
+  int ret = zend_parse_parameters(ZEND_NUM_ARGS(), "SS|ll", &zkey, &zvalue,
+                                  &_id, &_flag);
+  if (ret == FAILURE) {
     zend_error(E_ERROR, "pinpoint_add_clues() expects (int, string).");
     return;
   }
@@ -591,7 +610,9 @@ static inline zend_string *merge_pp_style_name(zend_string *scope,
     return zend_string_tolower(func);
   }
 }
-#if PHP_MAJOR_VERSION == 8 and PHP_MINOR_VERSION >= 2
+
+#if (PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION >= 2)
+
 // ref from php-8.2.19/ext/standard/var.c:137
 static zval *zend_array_index(zval *ar, int index) {
   HashTable *__ht = Z_ARRVAL_P(ar);
@@ -654,7 +675,7 @@ get_pp_style_function_name(zend_execute_data *execute_data) {
     zend_string *scope_name;
     if (func->common.scope) {
       scope_name = func->common.scope->name;
-#if PHP_MAJOR_VERSION == 7 and PHP_MINOR_VERSION <= 2
+#if PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION <= 2
     } else if (object->handlers->get_class_name ==
                std_object_handlers.get_class_name) {
 #else
@@ -856,7 +877,8 @@ static pp_interceptor_v_t *make_interceptor(zend_string *name, zval *before,
                                             zend_function *origin_func) {
   pp_interceptor_v_t *interceptor =
       (pp_interceptor_v_t *)malloc(sizeof(pp_interceptor_v_t));
-  bzero(interceptor, sizeof(*interceptor));
+  // bzero(interceptor, sizeof(*interceptor));
+  memset(interceptor, 0, sizeof(*interceptor));
   interceptor->name = zend_string_dup(name, 0);
   interceptor->origin = origin_func->internal_function.handler;
   interceptor->origin_func = origin_func;
@@ -1129,18 +1151,19 @@ PHP_FUNCTION(pinpoint_get_func_ref_args) {
 #endif
 
 PHP_FUNCTION(_pinpoint_trace_limit) {
-  long timestamp = -1;
-
+  // getchar();
+  double timestamp = -1;
 #if PHP_VERSION_ID < 70000
 
-  zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &timestamp);
+  zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|d", &timestamp);
 #else
-  zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &timestamp);
+  zend_parse_parameters(ZEND_NUM_ARGS(), "|d", &timestamp);
 #endif
 
-  timestamp = (timestamp == -1) ? (time(NULL)) : (timestamp);
+  int64_t timestamp_64 =
+      (timestamp == -1) ? (time(NULL)) : (static_cast<std::int64_t>(timestamp));
 
-  if (check_trace_limit(timestamp) == 1) {
+  if (check_trace_limit(timestamp_64) == 1) {
     RETURN_TRUE;
   } else {
     RETURN_FALSE;
diff --git a/pinpoint_php_files.txt b/pinpoint_php_files.txt
new file mode 100644
index 00000000..7e806231
--- /dev/null
+++ b/pinpoint_php_files.txt
@@ -0,0 +1,6 @@
+output/Release/php_pinpoint_php.dll
+output/Release/php_pinpoint_php.lib
+output/Release/php_pinpoint_php.pdb
+NOTICE
+README.md
+CHANGES-PHP.md


Test patch:
diff --git a/testapps/PHP/php.dockerfile b/testapps/PHP/php.dockerfile
index 4fc60ec5..858a9bbf 100644
--- a/testapps/PHP/php.dockerfile
+++ b/testapps/PHP/php.dockerfile
@@ -3,7 +3,8 @@ FROM yiisoftware/yii2-php:7.4-fpm-nginx
 
 # build ext
 COPY config.m4 /pinpoint-c-agent/config.m4 
-COPY src/PHP /pinpoint-c-agent/src/PHP
+COPY pinpoint_php.cpp /pinpoint-c-agent/pinpoint_php.cpp 
+COPY php_pinpoint_php.h /pinpoint-c-agent/php_pinpoint_php.h
 COPY common /pinpoint-c-agent/common
 COPY tests /pinpoint-c-agent/tests
 
diff --git a/testapps/SimplePHP/simplephp.dockerfile b/testapps/SimplePHP/simplephp.dockerfile
index 12bb232b..bb843ed8 100644
--- a/testapps/SimplePHP/simplephp.dockerfile
+++ b/testapps/SimplePHP/simplephp.dockerfile
@@ -14,7 +14,8 @@ RUN cd /tmp/ && git clone https://github.com/phpredis/phpredis.git && cd phpredi
 RUN cd /tmp/ && git clone https://github.com/php-memcached-dev/php-memcached.git && cd php-memcached && phpize && ./configure &&  make install
 RUN cd /tmp/ && git clone https://github.com/krakjoe/apcu.git && cd apcu && phpize && ./configure &&  make install
 COPY config.m4 /pinpoint-c-agent/config.m4 
-COPY src/PHP /pinpoint-c-agent/src/PHP
+COPY pinpoint_php.cpp /pinpoint-c-agent/pinpoint_php.cpp 
+COPY php_pinpoint_php.h /pinpoint-c-agent/php_pinpoint_php.h
 COPY common /pinpoint-c-agent/common
 COPY tests /pinpoint-c-agent/tests
 
diff --git a/testapps/cachethq/cachethq.dockerfile b/testapps/cachethq/cachethq.dockerfile
index 8a6e712b..cc6fb2a9 100644
--- a/testapps/cachethq/cachethq.dockerfile
+++ b/testapps/cachethq/cachethq.dockerfile
@@ -3,7 +3,8 @@ USER root
 RUN apk update && apk add --virtual build-dependencies build-base gcc wget git php7-dev
 ENV DB_DRIVER=pgsql
 COPY config.m4 /pinpoint-c-agent/config.m4 
-COPY src/PHP /pinpoint-c-agent/src/PHP
+COPY pinpoint_php.cpp /pinpoint-c-agent/pinpoint_php.cpp 
+COPY php_pinpoint_php.h /pinpoint-c-agent/php_pinpoint_php.h
 COPY common /pinpoint-c-agent/common
 COPY testapps/php_wordpress/pinpoint_php.ini /pinpoint-c-agent/pinpoint_php.ini
 
diff --git a/testapps/php_compatible.dockerfile b/testapps/php_compatible.dockerfile
index 75db44e5..b949356e 100644
--- a/testapps/php_compatible.dockerfile
+++ b/testapps/php_compatible.dockerfile
@@ -3,7 +3,8 @@ FROM  php:${PHP_VERSION}
 WORKDIR /pinpoint-c-agent/
 RUN apt update && apt install -y valgrind git
 COPY config.m4 /pinpoint-c-agent/config.m4 
-COPY src/PHP /pinpoint-c-agent/src/PHP
+COPY pinpoint_php.cpp /pinpoint-c-agent/pinpoint_php.cpp 
+COPY php_pinpoint_php.h /pinpoint-c-agent/php_pinpoint_php.h
 COPY common /pinpoint-c-agent/common
 COPY tests /pinpoint-c-agent/tests
 ENV NO_INTERACTION=1
diff --git a/testapps/php_compatible_older.dockerfile b/testapps/php_compatible_older.dockerfile
index c24e70aa..4b875493 100644
--- a/testapps/php_compatible_older.dockerfile
+++ b/testapps/php_compatible_older.dockerfile
@@ -3,7 +3,8 @@ FROM  php:${PHP_VERSION}
 WORKDIR /pinpoint-c-agent/
 RUN apt update && apt install -y valgrind git
 COPY config.m4 /pinpoint-c-agent/config.m4 
-COPY src/PHP /pinpoint-c-agent/src/PHP
+COPY pinpoint_php.cpp /pinpoint-c-agent/pinpoint_php.cpp 
+COPY php_pinpoint_php.h /pinpoint-c-agent/php_pinpoint_php.h
 COPY common /pinpoint-c-agent/common
 COPY tests /pinpoint-c-agent/tests
 ENV NO_INTERACTION=1
@@ -26,7 +27,8 @@ RUN  wget https://www.php.net/distributions/php-${PHP_VERSION}.tar.gz && tar xvf
 RUN  cd php-${PHP_VERSION} && ./configure --build=x86_64-linux-gnu --with-config-file-path=/usr/local/etc/php --with-config-file-scan-dir=/usr/local/etc/php/conf.d --enable-option-checking=fatal --with-mhash --enable-ftp --enable-mbstring --enable-mysqlnd --with-pdo-sqlite=/usr --with-sqlite3=/usr --with-curl  --with-openssl --with-zlib --with-libdir=lib/x86_64-linux-gnu build_alias=x86_64-linux-gnu && make -j && make install
 
 COPY config.m4 /pinpoint-c-agent/config.m4 
-COPY src/PHP /pinpoint-c-agent/src/PHP
+COPY pinpoint_php.cpp /pinpoint-c-agent/pinpoint_php.cpp 
+COPY php_pinpoint_php.h /pinpoint-c-agent/php_pinpoint_php.h
 COPY common /pinpoint-c-agent/common
 COPY tests /pinpoint-c-agent/tests
 ENV NO_INTERACTION=1
diff --git a/tests_macos/add_root_trace.phpt b/tests_macos/add_root_trace.phpt
new file mode 100644
index 00000000..5aad9b2c
--- /dev/null
+++ b/tests_macos/add_root_trace.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Test pinpoint_unique_id
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=-1
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+$id = _pinpoint_start_trace(0);
+_pinpoint_add_clue("name","Foo",$id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clues("global","global_value",$id,1);
+_pinpoint_add_clue("global","global_value",$id,1);
+_pinpoint_add_clues("name","Foo1",$id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clue("name","Foo2",$id);
+$id = _pinpoint_end_trace($id);
+$id = _pinpoint_end_trace($id);
+$id = _pinpoint_end_trace($id);
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+[pinpoint] [%d] [%d] [127] add clues:global:global_value
+[pinpoint] [%d] [%d] [127] add clue key:global value:global_value
+[pinpoint] [%d] [%d] [127] add clues:name:Foo1
+[pinpoint] [%d] [%d] [127] pinpoint_start child  [126]
+[pinpoint] [%d] [%d] [126] add clue key:name value:Foo2
+[pinpoint] [%d] [%d] [126] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"calls":[{":E":%d,":S":%d,"calls":[{":E":%d,":S":%d,"name":"Foo2"}],"clues":["name:Foo1"]}],"clues":["global:global_value"],"global":"global_value","name":"Foo"})
+[pinpoint] [%d] [%d][unittest] current span was dropped
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
\ No newline at end of file
diff --git a/tests_macos/aop_helper_api.phpt b/tests_macos/aop_helper_api.phpt
new file mode 100644
index 00000000..937e1742
--- /dev/null
+++ b/tests_macos/aop_helper_api.phpt
@@ -0,0 +1,194 @@
+--TEST--
+app info 
+--SKIPIF--
+<?php print "skip"; print "deprecated"?>
+--INI--
+pinpoint_php.DebugReport=false
+--FILE--
+<?php 
+
+## test in function
+function foo(&$a,$b,$c,$d)
+{
+    $ar = \pinpoint_get_func_ref_args();
+    var_dump($ar);
+    $ar[0] = "hello php!!!";
+    $ar[1] = 10;
+    $ar[2] = 10;
+    $ar[3] = 10;
+    
+}
+$var = 100;
+foo($var,1,3,4);
+var_dump($var);
+## global
+var_dump(\pinpoint_get_func_ref_args());
+
+## test in class
+class Foo{
+    public function __construct( $a,$b)
+    {
+        echo "call __construct \n";
+        var_dump(\pinpoint_get_func_ref_args());
+    }
+
+    public function __destruct()
+    {
+        echo "call __destruct \n";
+        var_dump(\pinpoint_get_func_ref_args()); 
+    }
+
+    public function test_none()
+    {
+        var_dump(\pinpoint_get_func_ref_args()); 
+    }
+
+    public function foo(string $a,int $b,array $ar,$c = 'hello pinpoint-php',$d=123.4534,$e=null)
+    {
+       $input = \pinpoint_get_func_ref_args();
+       var_dump($input);
+    }
+
+    public static function static_foo(string $a,int $b,array $ar,$c = 'hello pinpoint-php',$d=123.4534,$e=null)
+    {
+       $var =  \pinpoint_get_func_ref_args();
+       var_dump($var);
+    }
+
+    public  function return_all($a,$b,$c)
+    {
+        return \pinpoint_get_func_ref_args();
+    }
+
+}
+
+$foo = new Foo(1,2);
+$foo->foo('hello pinpoint',1,array('1'=>2,'c'=>3,'e'=>5));
+Foo::static_foo('hello pinpoint',1,array('1'=>2,'c'=>3,'e'=>5));
+$foo->test_none();
+var_dump($foo->return_all("23",1,null));
+
+echo "test anonymous \n";
+$name = 'eeliu';
+$nobody = function ($arg) use (&$name) {
+    var_dump(\pinpoint_get_func_ref_args());
+    $name = 'eeliu-01';
+    $arg = $arg.$name;
+    return \pinpoint_get_func_ref_args();
+};
+var_dump($nobody("hello "));
+echo "\n";
+
+echo "test pinpoint_get_func_ref_args call in call_user_func_array \n";
+
+function foo_ref($a,&$b,&$c)
+{
+    var_dump(func_get_args());
+    $b = 10;
+    $c = 11;
+    return array($b,$c);
+}
+
+function aop_foo_ref($a,&$b,&$c)
+{
+    $args = \pinpoint_get_func_ref_args();
+    return call_user_func_array('foo_ref',$args);
+}
+$b =2;
+$c = 12;
+var_dump(aop_foo_ref("adf",$b,$c));
+echo "b = $b \n";
+echo "c = $c \n";
+
+--EXPECTF--
+array(4) {
+  [0]=>
+  &int(100)
+  [1]=>
+  int(1)
+  [2]=>
+  int(3)
+  [3]=>
+  int(4)
+}
+string(12) "hello php!!!"
+
+Warning: pinpoint_get_func_ref_args():  Called from the global scope - no function context in %s on line 18
+bool(false)
+call __construct 
+array(2) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+}
+array(3) {
+  [0]=>
+  string(14) "hello pinpoint"
+  [1]=>
+  int(1)
+  [2]=>
+  array(3) {
+    [1]=>
+    int(2)
+    ["c"]=>
+    int(3)
+    ["e"]=>
+    int(5)
+  }
+}
+array(3) {
+  [0]=>
+  string(14) "hello pinpoint"
+  [1]=>
+  int(1)
+  [2]=>
+  array(3) {
+    [1]=>
+    int(2)
+    ["c"]=>
+    int(3)
+    ["e"]=>
+    int(5)
+  }
+}
+array(0) {
+}
+array(3) {
+  [0]=>
+  string(2) "23"
+  [1]=>
+  int(1)
+  [2]=>
+  NULL
+}
+test anonymous 
+array(1) {
+  [0]=>
+  string(6) "hello "
+}
+array(1) {
+  [0]=>
+  string(14) "hello eeliu-01"
+}
+
+test pinpoint_get_func_ref_args call in call_user_func_array 
+array(3) {
+  [0]=>
+  string(3) "adf"
+  [1]=>
+  int(2)
+  [2]=>
+  int(12)
+}
+array(2) {
+  [0]=>
+  int(10)
+  [1]=>
+  int(11)
+}
+b = 10 
+c = 11 
+call __destruct 
+array(0) {
+}
\ No newline at end of file
diff --git a/tests_macos/app_info_test.phpt b/tests_macos/app_info_test.phpt
new file mode 100644
index 00000000..7c7e1817
--- /dev/null
+++ b/tests_macos/app_info_test.phpt
@@ -0,0 +1,16 @@
+--TEST--
+app info 
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+var_dump(_pinpoint_start_time());
+var_dump("APP".'^'.strval(_pinpoint_start_time()).'^'.strval(_pinpoint_unique_id()));
+--EXPECTF--
+float(%d)
+string(%d) "APP^%d^%d"
\ No newline at end of file
diff --git a/tests_macos/drop_trace_test.phpt b/tests_macos/drop_trace_test.phpt
new file mode 100644
index 00000000..68da7e59
--- /dev/null
+++ b/tests_macos/drop_trace_test.phpt
@@ -0,0 +1,23 @@
+--TEST--
+drop this trace
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+_pinpoint_start_trace();
+_pinpoint_drop_trace();
+_pinpoint_add_clue("args",'a,$b');
+_pinpoint_add_clue("ret",'a,$b');
+_pinpoint_end_trace();
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d]change current [128] status, before:2,now:4
+[pinpoint] [%d] [%d] [128] add clue key:args value:a,$b
+[pinpoint] [%d] [%d] [128] add clue key:ret value:a,$b
+[pinpoint] [%d] [%d]current [128] span dropped,due to TRACE_BLOCK
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
\ No newline at end of file
diff --git a/tests_macos/mark_as_error.phpt b/tests_macos/mark_as_error.phpt
new file mode 100644
index 00000000..93800c28
--- /dev/null
+++ b/tests_macos/mark_as_error.phpt
@@ -0,0 +1,26 @@
+--TEST--
+pinpoint_php internal test case [pinpoint_test_main]
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=-1
+pinpoint_php.UnitTest=true
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+_pinpoint_start_trace();
+_pinpoint_add_clue("args",'a,$b');
+_pinpoint_add_clue("ret",'a,$b');
+_pinpoint_mark_as_error("message you cared","filename you cared",1023);
+echo _pinpoint_end_trace()."\n";
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] add clue key:args value:a,$b
+[pinpoint] [%d] [%d] [128] add clue key:ret value:a,$b
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"ERR":{"file":"filename you cared","line":1023,"msg":"message you cared"},"args":"a,$b","ret":"a,$b"})
+[pinpoint] [%d] [%d][unittest] current span was dropped
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+0
\ No newline at end of file
diff --git a/tests_macos/node_test.phpt b/tests_macos/node_test.phpt
new file mode 100644
index 00000000..24ac0276
--- /dev/null
+++ b/tests_macos/node_test.phpt
@@ -0,0 +1,35 @@
+--TEST--
+Test pinpoint_unique_id
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+
+$unexist_node = 1024;
+
+_pinpoint_start_trace($unexist_node);
+
+_pinpoint_add_clue("adf","fdfd",$unexist_node,0);
+_pinpoint_add_clue("adf","fdfd",$unexist_node,1);
+_pinpoint_set_context('b','b',$unexist_node);
+_pinpoint_add_clues(32,"fdfd",$unexist_node,1);
+_pinpoint_add_clues(32,"fdfd",$unexist_node,0);
+
+_pinpoint_get_context('b',$unexist_node);
+
+_pinpoint_end_trace($unexist_node);
+
+--EXPECTF--
+[pinpoint] [%d] [%d] start_trace [1024] failed with #1024 is not alive
+[pinpoint] [%d] [%d] pinpoint_add_clue [1024] failed. Reason: #1024 is not alive,parameters:adf:fdfd
+[pinpoint] [%d] [%d] pinpoint_add_clue [1024] failed. Reason: #1024 is not alive,parameters:adf:fdfd
+[pinpoint] [%d] [%d] pinpoint_set_context_key [1024] failed with out_of_range. #1024 is not alive,parameters:b:b
+[pinpoint] [%d] [%d] pinpoint_add_clues [1024] failed. Reason #1024 is not alive,parameters:32:fdfd
+[pinpoint] [%d] [%d] pinpoint_add_clues [1024] failed. Reason #1024 is not alive,parameters:32:fdfd
+[pinpoint] [%d] [%d] pinpoint_get_context_key [1024] failed with #1024 is not alive, parameters:b
+[pinpoint] [%d] [%d]end_trace 1024 out_of_range exception: #1024 is not alive
\ No newline at end of file
diff --git a/tests_macos/pinpoint_get_caller_arg.phpt b/tests_macos/pinpoint_get_caller_arg.phpt
new file mode 100644
index 00000000..9dfb10dd
--- /dev/null
+++ b/tests_macos/pinpoint_get_caller_arg.phpt
@@ -0,0 +1,63 @@
+--TEST--
+pinpoint_php test  pinpoint_get_caller_arg
+--SKIPIF--
+<?php 
+if (!extension_loaded("pinpoint_php")) 
+{   
+    print "skip"; 
+    print "pinpoint_php"; 
+}
+if (!extension_loaded("curl")) 
+{   
+    print "skip"; 
+    print "curl"; 
+}
+
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+curl
+--FILE--
+<?php
+
+_pinpoint_join_cut(
+    ["curl_exec"],
+    function ($a) {
+    },
+    function ($ret) {
+        $ch = pinpoint_get_caller_arg(0);
+        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+        echo "status_code $code \n";
+    },
+    function ($e) {
+    }
+);
+
+echo "case: curl_init() \n";
+
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, "http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:"xxxx"',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+
+$j_res = json_decode($response, true);
+
+$error = curl_error($ch);
+echo "error: $error\n";
+curl_close($ch);
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor function=curl_exec
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_exec success
+case: curl_init() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+status_code 200 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+[pinpoint] [%d] [%d]start free interceptor: curl_exec
\ No newline at end of file
diff --git a/tests_macos/pinpoint_get_this.phpt b/tests_macos/pinpoint_get_this.phpt
new file mode 100644
index 00000000..babd5089
--- /dev/null
+++ b/tests_macos/pinpoint_get_this.phpt
@@ -0,0 +1,61 @@
+--TEST--
+pinpoint_php test get this
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+
+class Foo{
+    public function output(){
+
+      $onBefore = function(){
+        $f = pinpoint_get_this();
+        if($f instanceof  Foo){
+          var_dump($f->abc);
+          var_dump($f->abc_s);
+          echo " update foo members \n";
+          $f->abc = 1234;
+          $f->abc_s= "hello pinpoint";
+        }
+      };
+
+      $onBefore();
+    }
+    public $abc = 123;
+    public $abc_s = "123";
+}
+
+$f = new Foo();
+$f->output();
+var_dump($f->abc);
+var_dump($f->abc_s);
+var_dump(pinpoint_get_this());
+
+echo "test static method \n";
+class S_Foo
+{
+    public static $my_static = 'foo';
+
+    public static function staticValue() {
+      $f = pinpoint_get_this();
+      var_dump($f);
+      return self::$my_static;
+    }
+}
+
+$sf = new S_Foo();
+S_Foo::staticValue();
+
+--EXPECTF--
+int(123)
+string(3) "123"
+ update foo members 
+int(1234)
+string(14) "hello pinpoint"
+[pinpoint] [%d] [%d]pinpoint_get_this: not support, no this
+bool(false)
+test static method 
+[pinpoint] [%d] [%d]pinpoint_get_this: not support, no this
+bool(false)
\ No newline at end of file
diff --git a/tests_macos/pinpoint_join_cut_curl_7.phpt b/tests_macos/pinpoint_join_cut_curl_7.phpt
new file mode 100644
index 00000000..72ef024d
--- /dev/null
+++ b/tests_macos/pinpoint_join_cut_curl_7.phpt
@@ -0,0 +1,233 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_cut
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("curl"))
+   print "skip";
+if (version_compare(phpversion(), '8.0.0', '>='))
+{    print "skip";
+    print "only works in php7";
+}
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}
+?>
+--INI--
+pinpoint_php.DebugReport=true
+
+--EXTENSIONS--
+json
+curl
+
+--FILE--
+<?php
+_pinpoint_join_cut(
+    ["curl_init"],
+    function ($a = null) {
+        echo "on_before \n";
+        var_dump($a);
+    },
+    function ($ret) {
+        echo "on_end \n";
+        var_dump($ret);
+        if (is_resource($ret)) {
+            echo "get resource ";
+            assert(curl_setopt($ret, CURLOPT_HEADER, false));
+        }
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    }
+);
+
+_pinpoint_join_cut(
+    ["curl_exec"],
+    function ($a) {
+        echo "on_before \n";
+        var_dump($a);
+        assert(is_resource($a));
+        echo "request url: " . curl_getinfo($a, CURLINFO_EFFECTIVE_URL) . "\n";
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    }
+);
+
+_pinpoint_join_cut(
+    ["curl_setopt"],
+    function ($ch, $option, $value) {
+        assert(is_resource($ch));
+        var_dump($option);
+
+        if ($option == CURLOPT_HTTPHEADER && is_array($value)) {
+            $value[] = "pinpoint_join_cut:xxxx";
+            $value[] = "pinpoint_join_cu2t:agc";
+            $value[] = "pinpoint_join_cus2t:agc";
+            $value[] = "pinpoint_join_cus2t2:agc";
+            echo "value must be affected\n";
+            return [$ch, $option, $value];
+        } else if ($option == CURLOPT_RETURNTRANSFER && is_bool($value)) {
+            echo "test CURLOPT_RETURNTRANSFER \n";
+            return [$ch, $option, 2];
+        } else if ($option == CURLOPT_URL && is_string($value)) {
+            echo "test CURLOPT_URL \n";
+            return [$ch, 2];
+        } else {
+            echo "not working";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    }
+);
+
+
+echo "case: curl_init() \n";
+
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, "http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:"xxxx"',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+
+$j_res = json_decode($response, true);
+
+assert($j_res["headers"]["Pinpoint-Join-Cu2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T2"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cut"] == "xxxx");
+
+$error = curl_error($ch);
+echo "error:$error \n";
+curl_close($ch);
+
+echo "case : curl_init with variable \n";
+$ch = curl_init("http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:"xxxx"',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+$j_res = json_decode($response, true);
+
+assert($j_res["headers"]["Pinpoint-Join-Cu2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T2"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cut"] == "xxxx");
+$error = curl_error($ch);
+echo "error:$error \n";
+curl_close($ch);
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor function=curl_init
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_init success
+[pinpoint] [%d] [%d]try to interceptor function=curl_exec
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_exec success
+[pinpoint] [%d] [%d]try to interceptor function=curl_setopt
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_setopt success
+case: curl_init() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_init
+on_before 
+NULL
+[pinpoint] [%d] [%d] call_interceptor_before:curl_init return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+resource(4) of type (curl)
+get resource [pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(42)
+not working[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_init 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10002)
+test CURLOPT_URL 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:2
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `size` does not matched
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(19913)
+test CURLOPT_RETURNTRANSFER 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `type` does not matched expected:3 give:4
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10023)
+value must be affected
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]args[2] type:7 in:1 va:2
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+on_before 
+resource(4) of type (curl)
+request url: http://httpbin.org/anything
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+case : curl_init with variable 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_init
+on_before 
+string(27) "http://httpbin.org/anything"
+[pinpoint] [%d] [%d] call_interceptor_before:curl_init return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+resource(5) of type (curl)
+get resource [pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(42)
+not working[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_init 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(19913)
+test CURLOPT_RETURNTRANSFER 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `type` does not matched expected:3 give:4
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10023)
+value must be affected
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]args[2] type:7 in:1 va:2
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+on_before 
+resource(5) of type (curl)
+request url: http://httpbin.org/anything
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+[pinpoint] [%d] [%d]start free interceptor: curl_init
+[pinpoint] [%d] [%d]start free interceptor: curl_exec
+[pinpoint] [%d] [%d]start free interceptor: curl_setopt
\ No newline at end of file
diff --git a/tests_macos/pinpoint_join_cut_curl_8.phpt b/tests_macos/pinpoint_join_cut_curl_8.phpt
new file mode 100644
index 00000000..ba1726d1
--- /dev/null
+++ b/tests_macos/pinpoint_join_cut_curl_8.phpt
@@ -0,0 +1,234 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_cut
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("curl"))
+   print "skip no curl";
+if (version_compare(phpversion(), '8.0.0', '<')){   
+    print "skip only works in php8";
+}
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}
+?>
+--INI--
+pinpoint_php.DebugReport=true
+
+--EXTENSIONS--
+json
+
+--FILE--
+<?php
+_pinpoint_join_cut(
+    ["curl_init"],
+    function ($a = null) {
+        echo "on_before \n";
+        var_dump($a);
+    },
+    function ($ret) {
+        echo "on_end \n";
+        var_dump($ret);
+        if ($ret instanceof CurlHandle) {
+            echo "get resource ";
+            assert(curl_setopt($ret, CURLOPT_HEADER, false));
+        }
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    },
+);
+
+_pinpoint_join_cut(
+    ["curl_exec"],
+    function ($a) {
+        echo "on_before \n";
+        var_dump($a);
+        assert($a instanceof CurlHandle);
+        echo "request url: " . curl_getinfo($a, CURLINFO_EFFECTIVE_URL) . "\n";
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    },
+);
+
+_pinpoint_join_cut(
+    ["curl_setopt"],
+    function ($ch, $option, $value) {
+        assert($ch instanceof CurlHandle);
+        var_dump($option);
+
+        if ($option == CURLOPT_HTTPHEADER && is_array($value)) {
+            $value[] = "pinpoint_join_cut:xxxx";
+            $value[] = "pinpoint_join_cu2t:agc";
+            $value[] = "pinpoint_join_cus2t:agc";
+            $value[] = "pinpoint_join_cus2t2:agc";
+            echo "value must be affected\n";
+            return [$ch, $option, $value];
+        } else if ($option == CURLOPT_RETURNTRANSFER && is_bool($value)) {
+            echo "test CURLOPT_RETURNTRANSFER \n";
+            return [$ch, $option, 2];
+        } else if ($option == CURLOPT_URL && is_string($value)) {
+            echo "test CURLOPT_URL \n";
+            return [$ch, 2];
+        } else {
+            echo "not working";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    },
+);
+
+
+echo "case: curl_init() \n";
+
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, "http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:xxxx',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+
+$j_res = json_decode($response, true);
+assert($j_res["headers"]["Pinpoint-Join-Cu2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T2"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cut"] == "xxxx");
+
+$error = curl_error($ch);
+echo "error:$error \n";
+curl_close($ch);
+
+echo "case : curl_init with variable \n";
+$ch = curl_init("http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:"xxxx"',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+$j_res = json_decode($response, true);
+
+assert($j_res["headers"]["Pinpoint-Join-Cu2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T2"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cut"] == "xxxx");
+$error = curl_error($ch);
+echo "error:$error \n";
+curl_close($ch);
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor function=curl_init
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_init success
+[pinpoint] [%d] [%d]try to interceptor function=curl_exec
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_exec success
+[pinpoint] [%d] [%d]try to interceptor function=curl_setopt
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_setopt success
+case: curl_init() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_init
+on_before 
+NULL
+[pinpoint] [%d] [%d] call_interceptor_before:curl_init return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+object(CurlHandle)#10 (0) {
+}
+get resource [pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(42)
+not working[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_init 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10002)
+test CURLOPT_URL 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:2
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `size` does not matched
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(19913)
+test CURLOPT_RETURNTRANSFER 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `type` does not matched expected:3 give:4
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10023)
+value must be affected
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]args[2] type:7 in:1 va:2
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+on_before 
+object(CurlHandle)#10 (0) {
+}
+request url: http://httpbin.org/anything
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+case : curl_init with variable 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_init
+on_before 
+string(27) "http://httpbin.org/anything"
+[pinpoint] [%d] [%d] call_interceptor_before:curl_init return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+object(CurlHandle)#11 (0) {
+}
+get resource [pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(42)
+not working[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_init 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(19913)
+test CURLOPT_RETURNTRANSFER 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `type` does not matched expected:3 give:4
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10023)
+value must be affected
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]args[2] type:7 in:1 va:2
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+on_before 
+object(CurlHandle)#11 (0) {
+}
+request url: http://httpbin.org/anything
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+[pinpoint] [%d] [%d]start free interceptor: curl_init
+[pinpoint] [%d] [%d]start free interceptor: curl_exec
+[pinpoint] [%d] [%d]start free interceptor: curl_setopt
\ No newline at end of file
diff --git a/tests_macos/pinpoint_join_cut_extend_pdo.phpt b/tests_macos/pinpoint_join_cut_extend_pdo.phpt
new file mode 100644
index 00000000..d1c61f04
--- /dev/null
+++ b/tests_macos/pinpoint_join_cut_extend_pdo.phpt
@@ -0,0 +1,156 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_pdo
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("pdo"))
+  print "skip";
+if (version_compare(phpversion(), '8.2.0', '>=')){
+  print "skip";
+  print phpversion() . ">= 8.2.0";
+}
+
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}
+
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+pdo_mysql
+--FILE--
+<?php
+
+_pinpoint_join_cut(
+    ["PDO", "__construct"],
+    function ($dsn, $username = null, $password = null, $options = null) {
+        echo "on_before: $dsn \n";
+        $pdo = pinpoint_get_this();
+        if ($pdo instanceof PDO) {
+            $pdo->dsn = $dsn;
+            echo "attached dsn \n";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+    }
+);
+
+$pdo_exec = "PDO::exec";
+_pinpoint_join_cut(
+    ["PDO", "exec"],
+    function ($statement) use ($pdo_exec) {
+        echo "$pdo_exec: on_before: $statement \n";
+    },
+    function ($ret) use ($pdo_exec) {
+        echo "$pdo_exec : on_end \n";
+    },
+    function ($e) use ($pdo_exec) {
+        echo "on_exception \n";
+    }
+);
+
+class MyPDO extends PDO
+{
+
+}
+$dbname = "employees";
+$pdo = new MyPDO("mysql:host=dev-mysql;dbname=$dbname", 'root', 'password');
+$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+$pdo->abc = "123";
+$sql = "CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' );";
+$ret = $pdo->exec($sql);
+if ($ret === false) {
+    echo "create pdo_test failed" . $pdo->errorCode();
+}
+
+$sql = "INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1);";
+$ret = $pdo->exec($sql);
+var_dump($ret);
+
+$unbufferedResult = $pdo->query("SELECT * FROM pdo_test");
+foreach ($unbufferedResult as $row) {
+    var_dump($unbufferedResult);
+}
+
+$sth = $pdo->prepare('SELECT name FROM pdo_test
+    WHERE AGE = :AGE limit 3');
+/* Names can be prefixed with colons ":" too (optional) */
+$sth->bindValue(':AGE', 1);
+$ret = $sth->execute();
+var_dump($ret);
+$ret = $sth->fetch();
+var_dump($ret);
+$ret = $sth->fetchAll();
+var_dump($ret);
+var_dump($pdo->abc);
+var_dump($pdo->dsn);
+$sql = 'DROP TABLE pdo_test';
+$ret = $pdo->exec($sql);
+
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:__construct
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::__construct success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:exec
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::exec success
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::__construct
+on_before: mysql:host=dev-mysql;dbname=employees 
+attached dsn 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::__construct return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::__construct 
+int(4)
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+bool(true)
+array(2) {
+  ["name"]=>
+  string(1) "a"
+  [0]=>
+  string(1) "a"
+}
+array(2) {
+  [0]=>
+  array(2) {
+    ["name"]=>
+    string(1) "b"
+    [0]=>
+    string(1) "b"
+  }
+  [1]=>
+  array(2) {
+    ["name"]=>
+    string(1) "d"
+    [0]=>
+    string(1) "d"
+  }
+}
+string(3) "123"
+string(37) "mysql:host=dev-mysql;dbname=employees"
+[pinpoint] [%d] [%d]start free interceptor: pdo::__construct
+[pinpoint] [%d] [%d]start free interceptor: pdo::exec
\ No newline at end of file
diff --git a/tests_macos/pinpoint_join_cut_mysqli.phpt b/tests_macos/pinpoint_join_cut_mysqli.phpt
new file mode 100644
index 00000000..08af04fb
--- /dev/null
+++ b/tests_macos/pinpoint_join_cut_mysqli.phpt
@@ -0,0 +1,90 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_mysqli
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if(getenv('SKIP_MACOS_ACTION', true)){
+  print "skip";
+}  
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+mysqli
+--FILE--
+
+<?php
+
+$on_before = function (...$args) {
+    $mysqli = pinpoint_get_this();
+    $db_host = "localhost";
+    if ($mysqli instanceof mysqli) {
+        $db_host = $mysqli->host_info;
+    }
+    echo "$db_host \n";
+};
+
+$on_before_func = function (...$args) {
+    $mysqli = $args[0];
+    $db_host = "localhost";
+    if ($mysqli instanceof mysqli) {
+        $db_host = $mysqli->host_info;
+    }
+    echo "$db_host \n";
+};
+
+$on_end = function ($ret) {
+
+};
+
+$on_exception = function ($exp) {
+};
+
+
+_pinpoint_join_cut(['mysqli_query'], $on_before_func, $on_end, $on_exception);
+_pinpoint_join_cut(['mysqli', 'query'], $on_before, $on_end, $on_exception);
+
+
+
+mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
+$mysqli = new mysqli();
+
+$mysqli->connect('dev-mysql', "root", "password", "employees", 3306);
+
+$result = $mysqli->query("SELECT * FROM `dept_emp_latest_date` LIMIT 1000;");
+printf("Select returned %d rows.\n", $result->num_rows);
+
+$stmt = $mysqli->prepare("SELECT * FROM employees WHERE emp_no=?");
+$id = 10005;
+$stmt->bind_param("i", $id);
+$stmt->execute();
+$stmt->fetch();
+$stmt->free_result();
+mysqli_query($mysqli, "SELECT * FROM `dept_emp_latest_date` LIMIT 1000;");
+
+$s_stmt = mysqli_prepare($mysqli, "SELECT * FROM employees WHERE emp_no=?");
+mysqli_stmt_bind_param($s_stmt, "i", $id);
+mysqli_stmt_execute($stmt);
+
+
+
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor function=mysqli_query
+[pinpoint] [%d] [%d]added interceptor on `function`: mysqli_query success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=mysqli:query
+[pinpoint] [%d] [%d]added interceptor on `module`: mysqli::query success
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:mysqli::query
+dev-mysql via TCP/IP 
+[pinpoint] [%d] [%d] call_interceptor_before:mysqli::query return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+[pinpoint] [%d] [%d]call_interceptor_end: mysqli::query 
+Select returned 1000 rows.
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:mysqli_query
+dev-mysql via TCP/IP 
+[pinpoint] [%d] [%d] call_interceptor_before:mysqli_query return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+[pinpoint] [%d] [%d]call_interceptor_end: mysqli_query 
+[pinpoint] [%d] [%d]start free interceptor: mysqli_query
+[pinpoint] [%d] [%d]start free interceptor: mysqli::query
\ No newline at end of file
diff --git a/tests_macos/pinpoint_join_cut_pdo.phpt b/tests_macos/pinpoint_join_cut_pdo.phpt
new file mode 100644
index 00000000..35df243e
--- /dev/null
+++ b/tests_macos/pinpoint_join_cut_pdo.phpt
@@ -0,0 +1,176 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_pdo
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("pdo"))
+  print "skip";
+if (version_compare(phpversion(), '8.2.0', '>=')){
+  print "skip";
+  print phpversion() . ">= 8.2.0";
+}
+if(getenv('SKIP_MACOS_ACTION', true)){
+  print "skip";
+}
+   
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+pdo_mysql
+--FILE--
+<?php
+
+_pinpoint_join_cut(
+    ["PDO", "__construct"],
+    function ($dsn, $username = null, $password = null, $options = null) {
+        echo "on_before: $dsn \n";
+        $pdo = pinpoint_get_this();
+        if ($pdo instanceof PDO) {
+            $pdo->dsn = $dsn;
+            echo "attached dsn \n";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+    }
+);
+$pdo_exec = "PDO::exec";
+_pinpoint_join_cut(
+    ["PDO", "exec"],
+    function ($statement) use ($pdo_exec) {
+        echo "$pdo_exec: on_before: $statement \n";
+    },
+    function ($ret) use ($pdo_exec) {
+        echo "$pdo_exec : on_end \n";
+    },
+    function ($e) use ($pdo_exec) {
+        echo "on_exception \n";
+    }
+);
+
+
+echo "case: pdo() \n";
+
+$dbname = "employees";
+$pdo = new PDO("mysql:host=dev-mysql;dbname=$dbname", 'root', 'password');
+$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+$pdo->abc = "123";
+$sql = "CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' );";
+$ret = $pdo->exec($sql);
+if ($ret === false) {
+    echo "create pdo_test failed" . $pdo->errorCode();
+}
+
+$sql = "INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1);";
+$ret = $pdo->exec($sql);
+var_dump($ret);
+
+$unbufferedResult = $pdo->query("SELECT * FROM pdo_test");
+foreach ($unbufferedResult as $row) {
+    var_dump($unbufferedResult);
+}
+
+$sth = $pdo->prepare('SELECT name FROM pdo_test
+    WHERE AGE = :AGE limit 3');
+/* Names can be prefixed with colons ":" too (optional) */
+$sth->bindValue(':AGE', 1);
+$ret = $sth->execute();
+var_dump($ret);
+$ret = $sth->fetch();
+var_dump($ret);
+$ret = $sth->fetchAll();
+var_dump($ret);
+var_dump($pdo->abc);
+var_dump($pdo->dsn);
+$sql = 'DROP TABLE pdo_test';
+$ret = $pdo->exec($sql);
+
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:__construct
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::__construct success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:exec
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::exec success
+case: pdo() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::__construct
+on_before: mysql:host=dev-mysql;dbname=employees 
+attached dsn 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::__construct return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::__construct 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' ); 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1); 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+int(4)
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+bool(true)
+array(2) {
+  ["name"]=>
+  string(1) "a"
+  [0]=>
+  string(1) "a"
+}
+array(2) {
+  [0]=>
+  array(2) {
+    ["name"]=>
+    string(1) "b"
+    [0]=>
+    string(1) "b"
+  }
+  [1]=>
+  array(2) {
+    ["name"]=>
+    string(1) "d"
+    [0]=>
+    string(1) "d"
+  }
+}
+string(3) "123"
+string(37) "mysql:host=dev-mysql;dbname=employees"
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: DROP TABLE pdo_test 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+[pinpoint] [%d] [%d]start free interceptor: pdo::__construct
+[pinpoint] [%d] [%d]start free interceptor: pdo::exec
\ No newline at end of file
diff --git a/tests_macos/pinpoint_join_cut_pdo_8.phpt b/tests_macos/pinpoint_join_cut_pdo_8.phpt
new file mode 100644
index 00000000..73b3c2f1
--- /dev/null
+++ b/tests_macos/pinpoint_join_cut_pdo_8.phpt
@@ -0,0 +1,187 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_pdo_8
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("pdo"))
+  print "skip";
+if (version_compare(phpversion(), '8.2.0', '<'))
+{   
+    print "skip";
+  print phpversion() ."< 8.2.0";
+}
+if(getenv('SKIP_MACOS_ACTION', true)){
+  print "skip";
+}
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+pdo_mysql
+
+--FILE--
+<?php
+
+$weakMap = new WeakMap();
+
+_pinpoint_join_cut(
+    ["PDO", "__construct"],
+    function ($dsn, $username = null, $password = null, $options = null) use ($weakMap) {
+        echo "on_before: $dsn \n";
+        $pdo = pinpoint_get_this();
+        if ($pdo instanceof PDO) {
+            $weakMap[$pdo] = $dsn;
+            echo "attached dsn \n";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+    }
+);
+$pdo_exec = "PDO::exec";
+_pinpoint_join_cut(
+    ["PDO", "exec"],
+    function ($statement) use ($pdo_exec, $weakMap) {
+
+        echo "$pdo_exec: on_before: $statement \n";
+
+        $pdo = pinpoint_get_this();
+        if ($pdo instanceof PDO) {
+            echo "$weakMap[$pdo] \n";
+        }
+
+    },
+    function ($ret) use ($pdo_exec) {
+        echo "$pdo_exec : on_end \n";
+    },
+    function ($e) use ($pdo_exec) {
+        echo "on_exception \n";
+    }
+);
+
+
+echo "case: pdo() \n";
+
+$dbname = "employees";
+$pdo = new PDO("mysql:host=dev-mysql;dbname=$dbname", 'root', 'password');
+$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+$sql = "CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' );";
+$ret = $pdo->exec($sql);
+if ($ret === false) {
+    echo "create pdo_test failed" . $pdo->errorCode();
+}
+
+$sql = "INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1);";
+$ret = $pdo->exec($sql);
+var_dump($ret);
+
+$unbufferedResult = $pdo->query("SELECT * FROM pdo_test");
+foreach ($unbufferedResult as $row) {
+    var_dump($unbufferedResult);
+}
+
+$sth = $pdo->prepare('SELECT name FROM pdo_test
+    WHERE AGE = :AGE limit 3');
+/* Names can be prefixed with colons ":" too (optional) */
+$sth->bindValue(':AGE', 1);
+$ret = $sth->execute();
+var_dump($ret);
+$ret = $sth->fetch();
+var_dump($ret);
+$ret = $sth->fetchAll();
+var_dump($ret);
+var_dump($weakMap[$pdo]);
+$sql = 'DROP TABLE pdo_test';
+$ret = $pdo->exec($sql);
+
+
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:__construct
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::__construct success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:exec
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::exec success
+case: pdo() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::__construct
+on_before: mysql:host=dev-mysql;dbname=employees 
+attached dsn 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::__construct return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::__construct 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' ); 
+mysql:host=dev-mysql;dbname=employees 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1); 
+mysql:host=dev-mysql;dbname=employees 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+int(4)
+object(PDOStatement)#9 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#9 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#9 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#9 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+bool(true)
+array(2) {
+  ["name"]=>
+  string(1) "a"
+  [0]=>
+  string(1) "a"
+}
+array(2) {
+  [0]=>
+  array(2) {
+    ["name"]=>
+    string(1) "b"
+    [0]=>
+    string(1) "b"
+  }
+  [1]=>
+  array(2) {
+    ["name"]=>
+    string(1) "d"
+    [0]=>
+    string(1) "d"
+  }
+}
+string(37) "mysql:host=dev-mysql;dbname=employees"
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: DROP TABLE pdo_test 
+mysql:host=dev-mysql;dbname=employees 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+[pinpoint] [%d] [%d]start free interceptor: pdo::__construct
+[pinpoint] [%d] [%d]start free interceptor: pdo::exec
\ No newline at end of file
diff --git a/tests_macos/pinpoint_join_cut_redis.phpt b/tests_macos/pinpoint_join_cut_redis.phpt
new file mode 100644
index 00000000..a6ab9803
--- /dev/null
+++ b/tests_macos/pinpoint_join_cut_redis.phpt
@@ -0,0 +1,295 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_redis
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+
+if (!extension_loaded("redis"))
+  print "skip";
+
+if (version_compare(phpversion(), '7.1.33', '<='))
+   print "skip";
+
+if(getenv('SKIP_MACOS_ACTION', true)){
+  print "skip";
+}
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+json
+redis
+--FILE--
+<?php
+function make_method_plugins_var_2($class_name, $method_name)
+{
+    //  connect 
+    $interceptor_name = "$class_name::$method_name";
+    $on_before_2 = function ($key, $value) use ($interceptor_name) {
+        echo "$interceptor_name before: $key : $value \n";
+    };
+
+    $on_end = function ($ret) use ($interceptor_name) {
+        echo "$interceptor_name end \n";
+    };
+
+    $on_exception = function ($exp) use ($interceptor_name) {
+        echo "$interceptor_name exception \n";
+    };
+
+    return [$class_name, $method_name, $on_before_2, $on_end, $on_exception];
+}
+
+function make_method_plugins_var_1($class_name, $method_name)
+{
+    $interceptor_name = "$class_name::$method_name";
+
+    $on_before_1 = function ($key = null) use ($interceptor_name) {
+        echo "$interceptor_name before: $key \n";
+    };
+
+    $on_end = function ($ret) use ($interceptor_name) {
+        echo "$interceptor_name end \n";
+    };
+
+    $on_exception = function ($exp) use ($interceptor_name) {
+        echo "$interceptor_name exception \n";
+    };
+
+    return [$class_name, $method_name, $on_before_1, $on_end, $on_exception];
+}
+
+function make_method_plugins_var_3($class_name, $method_name)
+{
+    $interceptor_name = "$class_name::$method_name";
+
+    $on_before_1 = function ($key, $_1, $_2) use ($interceptor_name) {
+        echo "$interceptor_name before: $key \n";
+    };
+
+    $on_end = function ($ret) use ($interceptor_name) {
+        echo "$interceptor_name end \n";
+    };
+
+    $on_exception = function ($exp) use ($interceptor_name) {
+        echo "$interceptor_name exception \n";
+    };
+
+    return [$class_name, $method_name, $on_before_1, $on_end, $on_exception];
+}
+
+
+function make_method_plugins_var_ar($class_name, $method_name)
+{
+    $interceptor_name = "$class_name::$method_name";
+
+    $on_before_1 = function ($ar) use ($interceptor_name) {
+        echo "$interceptor_name before:  \n";
+    };
+
+    $on_end = function ($ret) use ($interceptor_name) {
+        echo "$interceptor_name end \n";
+    };
+
+    $on_exception = function ($exp) use ($interceptor_name) {
+        echo "$interceptor_name exception \n";
+    };
+
+    return [$class_name, $method_name, $on_before_1, $on_end, $on_exception];
+}
+
+$points = [
+    make_method_plugins_var_1("Redis", "info"),
+    make_method_plugins_var_1("Redis", "get"),
+    make_method_plugins_var_2("Redis", "set"),
+    make_method_plugins_var_2("Redis", "setNx"),
+    make_method_plugins_var_2("Redis", "append"),
+    make_method_plugins_var_3("Redis", "getRange"),
+    make_method_plugins_var_3("Redis", "setRange"),
+    make_method_plugins_var_1("Redis", "strlen"),
+    make_method_plugins_var_2("Redis", "getBit"),
+    make_method_plugins_var_3("Redis", "setBit"),
+    make_method_plugins_var_ar("Redis", "mSet"),
+    make_method_plugins_var_ar("Redis", "mSetNx"),
+];
+
+foreach ($points as $point) {
+    _pinpoint_join_cut(
+        [$point[0], $point[1]],
+        $point[2],
+        $point[3],
+        $point[4]
+    );
+}
+
+
+echo "case: redis(xxx) \n";
+
+$redis = new Redis([
+    'host' => 'redis',
+    'port' => 6379,
+    'connectTimeout' => 2.5
+]);
+assert($redis->info() !== false);
+
+echo "case: redis() \n";
+$redis = new Redis();
+$redis->connect('redis', 6379);
+assert($redis->info() !== false);
+
+echo "case: redis() \n";
+$redis = new Redis();
+$redis->pconnect('redis', 6379);
+assert($redis->info() !== false);
+
+echo "case: strings \n";
+$redis = new Redis();
+$redis->pconnect('redis', 6379);
+$redis->get("a");
+$redis->set("a", "b");
+$redis->setNx("a", "10");
+$redis->append("ar", "aa");
+$redis->setRange("ar", 0, "bb");
+$redis->get("ar");
+$redis->getRange("ar", 0, 2);
+$redis->strlen("ar");
+$redis->getBit("ar", 1);
+$redis->setBit("ar", 1, 3);
+var_dump($redis->get("ar"));
+$redis->mSet(['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz']);
+var_dump($redis->exists('foo', 'bar', 'baz', 'not exists')); 
+$redis->flushdb();
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:info
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::info success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:get
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::get success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:set
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::set success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:setnx
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::setnx success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:append
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::append success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:getrange
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::getrange success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:setrange
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::setrange success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:strlen
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::strlen success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:getbit
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::getbit success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:setbit
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::setbit success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:mset
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::mset success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:msetnx
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::msetnx success
+case: redis(xxx) 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::info
+Redis::info before:  
+[pinpoint] [%d] [%d] call_interceptor_before:redis::info return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::info end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::info 
+case: redis() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::info
+Redis::info before:  
+[pinpoint] [%d] [%d] call_interceptor_before:redis::info return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::info end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::info 
+case: redis() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::info
+Redis::info before:  
+[pinpoint] [%d] [%d] call_interceptor_before:redis::info return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::info end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::info 
+case: strings 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::get
+Redis::get before: a 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::get return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::get end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::get 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::set
+Redis::set before: a : b 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::set return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::set end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::set 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::setnx
+Redis::setNx before: a : 10 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::setnx return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::setNx end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::setnx 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::append
+Redis::append before: ar : aa 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::append return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::append end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::append 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::setrange
+Redis::setRange before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::setrange return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::setRange end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::setrange 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::get
+Redis::get before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::get return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::get end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::get 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::getrange
+Redis::getRange before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::getrange return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::getRange end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::getrange 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::strlen
+Redis::strlen before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::strlen return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::strlen end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::strlen 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::getbit
+Redis::getBit before: ar : 1 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::getbit return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::getBit end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::getbit 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::setbit
+Redis::setBit before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::setbit return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::setBit end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::setbit 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::get
+Redis::get before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::get return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::get end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::get 
+string(2) "bb"
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::mset
+Redis::mSet before:  
+[pinpoint] [%d] [%d] call_interceptor_before:redis::mset return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::mSet end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::mset 
+int(3)
+[pinpoint] [%d] [%d]start free interceptor: redis::info
+[pinpoint] [%d] [%d]start free interceptor: redis::get
+[pinpoint] [%d] [%d]start free interceptor: redis::set
+[pinpoint] [%d] [%d]start free interceptor: redis::setnx
+[pinpoint] [%d] [%d]start free interceptor: redis::append
+[pinpoint] [%d] [%d]start free interceptor: redis::getrange
+[pinpoint] [%d] [%d]start free interceptor: redis::setrange
+[pinpoint] [%d] [%d]start free interceptor: redis::strlen
+[pinpoint] [%d] [%d]start free interceptor: redis::getbit
+[pinpoint] [%d] [%d]start free interceptor: redis::setbit
+[pinpoint] [%d] [%d]start free interceptor: redis::mset
+[pinpoint] [%d] [%d]start free interceptor: redis::msetnx
\ No newline at end of file
diff --git a/tests_macos/stack_fetal_error.phpt b/tests_macos/stack_fetal_error.phpt
new file mode 100644
index 00000000..1a390eb8
--- /dev/null
+++ b/tests_macos/stack_fetal_error.phpt
@@ -0,0 +1,62 @@
+--TEST--
+pinpoint_php internal test case [pinpoint_test_main]
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=-1
+pinpoint_php.UnitTest=true
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+
+class Foo{
+    public  function __construct()
+    {
+        _pinpoint_start_trace();
+        _pinpoint_add_clue("name","Foo");
+    }
+
+    public function __destruct()
+    {
+        _pinpoint_end_trace();
+    }
+
+    public function ouput($a,$b)
+    {
+        _pinpoint_add_clues("1","$a,$b");
+        _pinpoint_add_clues("2","234");
+    }
+}
+
+function Test(){
+    throw new \Exception("I am testting");
+}
+
+_pinpoint_start_trace();
+
+try{
+    $f = new Foo();
+    Test();
+}catch(\Exception $e){
+    throw $e;
+}
+
+_pinpoint_start_trace();
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+[pinpoint] [%d] [%d] [127] add clue key:name value:Foo
+[pinpoint] [%d] [%d]apm_error_cb called
+
+Fatal error: Uncaught Exception: I am testting in %s:23
+Stack trace:
+#0 %s(30): Test()
+#1 {main}
+  thrown in %s on line 23
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"ERR":{"file":"%s","line":23,"msg":"Uncaught Exception: I am testting in %s:23\nStack trace:\n#0 %s(30): Test()\n#1 {main}\n  thrown"},"calls":[{":E":%d,":S":%d,"name":"Foo"}]})
+[pinpoint] [%d] [%d][unittest] current span was dropped
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
\ No newline at end of file
diff --git a/tests_macos/trace_api_context_tcp.phpt b/tests_macos/trace_api_context_tcp.phpt
new file mode 100644
index 00000000..7df43656
--- /dev/null
+++ b/tests_macos/trace_api_context_tcp.phpt
@@ -0,0 +1,70 @@
+--TEST--
+Check  call statck
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:127.0.0.1:9999
+pinpoint_php.SendSpanTimeOutMs=-1
+pinpoint_php.UnitTest=true
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+
+
+_pinpoint_start_trace();
+
+_pinpoint_set_context('a','a');
+var_dump(_pinpoint_get_context('a'));
+_pinpoint_set_context('b','b');
+var_dump(_pinpoint_get_context('b'));
+
+_pinpoint_set_context('c','c');
+var_dump(_pinpoint_get_context('c'));
+
+var_dump(_pinpoint_get_context('not exist'));
+
+_pinpoint_end_trace();
+
+$id = _pinpoint_start_trace(0);
+$id = _pinpoint_start_trace($id);
+_pinpoint_set_context('a','a',$id);
+_pinpoint_set_context('b','b',$id);
+_pinpoint_set_context('c','c',$id);
+
+var_dump(_pinpoint_get_context('c',$id));
+var_dump(_pinpoint_get_context('b',$id));
+var_dump(_pinpoint_get_context('a',$id));
+var_dump(_pinpoint_get_context('not exist',$id));
+
+$id = _pinpoint_end_trace($id);
+_pinpoint_end_trace($id);
+pinpoint_status();
+?>
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+string(1) "a"
+string(1) "b"
+string(1) "c"
+[pinpoint] [%d] [%d] pinpoint_get_context_key [128] failed with map::at:  key not found, parameters:not exist
+bool(false)
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d})
+[pinpoint] [%d] [%d][unittest] current span was dropped
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+string(1) "c"
+string(1) "b"
+string(1) "a"
+[pinpoint] [%d] [%d] pinpoint_get_context_key [127] failed with map::at:  key not found, parameters:not exist
+bool(false)
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"calls":[{":E":%d,":S":%d}]})
+[pinpoint] [%d] [%d][unittest] current span was dropped
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+{
+	"common_library_version" : "%s",
+	"pool_free_node" : 128,
+	"pool_total_node" : 128
+}
\ No newline at end of file
diff --git a/tests_macos/trace_api_test.phpt b/tests_macos/trace_api_test.phpt
new file mode 100644
index 00000000..362d035a
--- /dev/null
+++ b/tests_macos/trace_api_test.phpt
@@ -0,0 +1,134 @@
+--TEST--
+Check  call statck
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+
+class Foo{
+    public  function __construct()
+    {
+        echo _pinpoint_start_trace()."\n";
+        _pinpoint_add_clue("name","Foo");
+    }
+
+    public function __destruct()
+    {
+        echo _pinpoint_end_trace()."\n";
+    }
+
+    public function ouput($a,$b)
+    {
+        _pinpoint_add_clues("1","$a,$b");
+        _pinpoint_add_clues("2","234");
+    }
+}
+
+function ouput_234($a,$b)
+{
+     $foo = new Foo();
+     $foo->ouput("234",3432);
+     usleep(2000);
+}
+
+
+echo _pinpoint_start_trace()."\n";
+
+_pinpoint_add_clue("name","ouput_234");
+for($x = 0;$x <10;$x++){
+    ouput_234(1,3);
+}
+_pinpoint_add_clue("args",'a,$b');
+_pinpoint_add_clue("ret",'a,$b');
+
+echo _pinpoint_end_trace()."\n";
+
+
+?>
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+128
+[pinpoint] [%d] [%d] [128] add clue key:name value:ouput_234
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+127
+[pinpoint] [%d] [%d] [127] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [127] add clues:1:234,3432
+[pinpoint] [%d] [%d] [127] add clues:2:234
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [126]
+126
+[pinpoint] [%d] [%d] [126] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [126] add clues:1:234,3432
+[pinpoint] [%d] [%d] [126] add clues:2:234
+[pinpoint] [%d] [%d] [126] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [125]
+125
+[pinpoint] [%d] [%d] [125] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [125] add clues:1:234,3432
+[pinpoint] [%d] [%d] [125] add clues:2:234
+[pinpoint] [%d] [%d] [125] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [124]
+124
+[pinpoint] [%d] [%d] [124] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [124] add clues:1:234,3432
+[pinpoint] [%d] [%d] [124] add clues:2:234
+[pinpoint] [%d] [%d] [124] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [123]
+123
+[pinpoint] [%d] [%d] [123] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [123] add clues:1:234,3432
+[pinpoint] [%d] [%d] [123] add clues:2:234
+[pinpoint] [%d] [%d] [123] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [122]
+122
+[pinpoint] [%d] [%d] [122] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [122] add clues:1:234,3432
+[pinpoint] [%d] [%d] [122] add clues:2:234
+[pinpoint] [%d] [%d] [122] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [121]
+121
+[pinpoint] [%d] [%d] [121] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [121] add clues:1:234,3432
+[pinpoint] [%d] [%d] [121] add clues:2:234
+[pinpoint] [%d] [%d] [121] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [120]
+120
+[pinpoint] [%d] [%d] [120] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [120] add clues:1:234,3432
+[pinpoint] [%d] [%d] [120] add clues:2:234
+[pinpoint] [%d] [%d] [120] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [119]
+119
+[pinpoint] [%d] [%d] [119] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [119] add clues:1:234,3432
+[pinpoint] [%d] [%d] [119] add clues:2:234
+[pinpoint] [%d] [%d] [119] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [118]
+118
+[pinpoint] [%d] [%d] [118] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [118] add clues:1:234,3432
+[pinpoint] [%d] [%d] [118] add clues:2:234
+[pinpoint] [%d] [%d] [118] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] add clue key:args value:a,$b
+[pinpoint] [%d] [%d] [128] add clue key:ret value:a,$b
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"args":"a,$b","calls":[{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"}],"name":"ouput_234","ret":"a,$b"})
+[pinpoint] [%d] [%d]agent try to connect:(localhost:10000)
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+0
\ No newline at end of file
diff --git a/tests_macos/trace_api_with_id.phpt b/tests_macos/trace_api_with_id.phpt
new file mode 100644
index 00000000..0393917b
--- /dev/null
+++ b/tests_macos/trace_api_with_id.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Test pinpoint_unique_id
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=-1
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+$id = 0;
+
+function exception_handler($exception) {
+    global $id;
+
+    $lastId = $id;
+    _pinpoint_add_clue("EXP",$exception->getMessage(),$id);
+
+    do
+    {
+        $lastId = _pinpoint_end_trace($lastId);
+    }while($lastId != 0);
+    echo "Uncaught exception: " , $exception->getMessage(), "\n";
+}
+
+set_exception_handler('exception_handler');
+
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clue("name","Foo",$id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clues("name","Foo1",$id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clue("name","Foo2",$id);
+$id = _pinpoint_end_trace($id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clues("name","Foo3",$id);
+_pinpoint_add_clue("name","Foo4",$id);
+$id = _pinpoint_end_trace($id);
+_pinpoint_add_clues("name","Foo5",$id);
+throw  new Exception("too heavy, throw it");
+$id = _pinpoint_end_trace($id);
+_pinpoint_add_clue("name","Foo",$id);
+
+$id = _pinpoint_end_trace($id);
+
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+[pinpoint] [%d] [%d] [127] add clues:name:Foo1
+[pinpoint] [%d] [%d] [127] pinpoint_start child  [126]
+[pinpoint] [%d] [%d] [126] add clue key:name value:Foo2
+[pinpoint] [%d] [%d] [126] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d] [127] pinpoint_start child  [125]
+[pinpoint] [%d] [%d] [125] add clues:name:Foo3
+[pinpoint] [%d] [%d] [125] add clue key:name value:Foo4
+[pinpoint] [%d] [%d] [125] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d] [127] add clues:name:Foo5
+[pinpoint] [%d] [%d] [127] add clue key:EXP value:too heavy, throw it
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"calls":[{":E":%d,":S":%d,"EXP":"too heavy, throw it","calls":[{":E":%d,":S":%d,"name":"Foo2"},{":E":%d,":S":%d,"clues":["name:Foo3"],"name":"Foo4"}],"clues":["name:Foo1","name:Foo5"]}],"name":"Foo"})
+[pinpoint] [%d] [%d][unittest] current span was dropped
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+Uncaught exception: too heavy, throw it
\ No newline at end of file
diff --git a/tests_macos/trace_limit_test-i448.phpt b/tests_macos/trace_limit_test-i448.phpt
new file mode 100644
index 00000000..8cabc233
--- /dev/null
+++ b/tests_macos/trace_limit_test-i448.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Check tracelimit
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=200
+pinpoint_php.UnitTest=true
+pinpoint_php.TraceLimit=0
+;pinpoint_php._limit for internal use. does not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+
+$id = _pinpoint_start_trace(0);
+$id = _pinpoint_start_trace($id);
+_pinpoint_set_context('a','a',$id);
+_pinpoint_set_context('b','b',$id);
+_pinpoint_set_context('c','c',$id);
+
+var_dump(_pinpoint_get_context('c',$id));
+var_dump(_pinpoint_get_context('b',$id));
+var_dump(_pinpoint_get_context('a',$id));
+var_dump(_pinpoint_get_context('not exist',$id));
+
+$id = _pinpoint_end_trace($id);
+
+if(_pinpoint_trace_limit())
+{
+   _pinpoint_drop_trace($id);
+}
+
+_pinpoint_end_trace($id);
+
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+string(1) "c"
+string(1) "b"
+string(1) "a"
+[pinpoint] [%d] [%d] pinpoint_get_context_key [127] failed with map::at:  key not found, parameters:not exist
+bool(false)
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]This span dropped. max_trace_limit:0 current_tick:0 onLine:0
+[pinpoint] [%d] [%d]change current [128] status, before:2,now:4
+[pinpoint] [%d] [%d]current [128] span dropped,due to TRACE_BLOCK
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
\ No newline at end of file
diff --git a/tests_macos/trace_limit_test.phpt b/tests_macos/trace_limit_test.phpt
new file mode 100644
index 00000000..40162c5c
--- /dev/null
+++ b/tests_macos/trace_limit_test.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Check tracelimit
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=200
+pinpoint_php.UnitTest=true
+pinpoint_php.TraceLimit=2
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+if(_pinpoint_trace_limit() || _pinpoint_trace_limit() ||_pinpoint_trace_limit() || _pinpoint_trace_limit())
+{
+    echo "pass";
+}else{
+    echo "_pinpoint_trace_limit failed";
+}
+--EXPECTF--
+[pinpoint] [%d] [%d]This span dropped. max_trace_limit:2 current_tick:2 onLine:0
+pass
\ No newline at end of file
diff --git a/tests_macos/unique_api_test.phpt b/tests_macos/unique_api_test.phpt
new file mode 100644
index 00000000..b2ce343d
--- /dev/null
+++ b/tests_macos/unique_api_test.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Test pinpoint_unique_id
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+ 
+$v1= _pinpoint_unique_id();
+$v2= _pinpoint_unique_id();
+$v3= _pinpoint_unique_id();
+var_dump( $v2*2 === $v1+$v3 );
+
+--EXPECTF--
+bool(true)
\ No newline at end of file
diff --git a/tests_win32/add_root_trace.phpt b/tests_win32/add_root_trace.phpt
new file mode 100644
index 00000000..be0fbbca
--- /dev/null
+++ b/tests_win32/add_root_trace.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Test pinpoint_unique_id
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+$id = _pinpoint_start_trace(0);
+_pinpoint_add_clue("name","Foo",$id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clues("global","global_value",$id,1);
+_pinpoint_add_clue("global","global_value",$id,1);
+_pinpoint_add_clues("name","Foo1",$id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clue("name","Foo2",$id);
+$id = _pinpoint_end_trace($id);
+$id = _pinpoint_end_trace($id);
+$id = _pinpoint_end_trace($id);
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+[pinpoint] [%d] [%d] [127] add clues:global:global_value
+[pinpoint] [%d] [%d] [127] add clue key:global value:global_value
+[pinpoint] [%d] [%d] [127] add clues:name:Foo1
+[pinpoint] [%d] [%d] [127] pinpoint_start child  [126]
+[pinpoint] [%d] [%d] [126] add clue key:name value:Foo2
+[pinpoint] [%d] [%d] [126] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"calls":[{":E":%d,":S":%d,"calls":[{":E":%d,":S":%d,"name":"Foo2"}],"clues":["name:Foo1"]}],"clues":["global:global_value"],"global":"global_value","name":"Foo"})
+[pinpoint] [%d] [%d]agent try to connect:(localhost:10000)
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
\ No newline at end of file
diff --git a/tests_win32/aop_helper_api.phpt b/tests_win32/aop_helper_api.phpt
new file mode 100644
index 00000000..937e1742
--- /dev/null
+++ b/tests_win32/aop_helper_api.phpt
@@ -0,0 +1,194 @@
+--TEST--
+app info 
+--SKIPIF--
+<?php print "skip"; print "deprecated"?>
+--INI--
+pinpoint_php.DebugReport=false
+--FILE--
+<?php 
+
+## test in function
+function foo(&$a,$b,$c,$d)
+{
+    $ar = \pinpoint_get_func_ref_args();
+    var_dump($ar);
+    $ar[0] = "hello php!!!";
+    $ar[1] = 10;
+    $ar[2] = 10;
+    $ar[3] = 10;
+    
+}
+$var = 100;
+foo($var,1,3,4);
+var_dump($var);
+## global
+var_dump(\pinpoint_get_func_ref_args());
+
+## test in class
+class Foo{
+    public function __construct( $a,$b)
+    {
+        echo "call __construct \n";
+        var_dump(\pinpoint_get_func_ref_args());
+    }
+
+    public function __destruct()
+    {
+        echo "call __destruct \n";
+        var_dump(\pinpoint_get_func_ref_args()); 
+    }
+
+    public function test_none()
+    {
+        var_dump(\pinpoint_get_func_ref_args()); 
+    }
+
+    public function foo(string $a,int $b,array $ar,$c = 'hello pinpoint-php',$d=123.4534,$e=null)
+    {
+       $input = \pinpoint_get_func_ref_args();
+       var_dump($input);
+    }
+
+    public static function static_foo(string $a,int $b,array $ar,$c = 'hello pinpoint-php',$d=123.4534,$e=null)
+    {
+       $var =  \pinpoint_get_func_ref_args();
+       var_dump($var);
+    }
+
+    public  function return_all($a,$b,$c)
+    {
+        return \pinpoint_get_func_ref_args();
+    }
+
+}
+
+$foo = new Foo(1,2);
+$foo->foo('hello pinpoint',1,array('1'=>2,'c'=>3,'e'=>5));
+Foo::static_foo('hello pinpoint',1,array('1'=>2,'c'=>3,'e'=>5));
+$foo->test_none();
+var_dump($foo->return_all("23",1,null));
+
+echo "test anonymous \n";
+$name = 'eeliu';
+$nobody = function ($arg) use (&$name) {
+    var_dump(\pinpoint_get_func_ref_args());
+    $name = 'eeliu-01';
+    $arg = $arg.$name;
+    return \pinpoint_get_func_ref_args();
+};
+var_dump($nobody("hello "));
+echo "\n";
+
+echo "test pinpoint_get_func_ref_args call in call_user_func_array \n";
+
+function foo_ref($a,&$b,&$c)
+{
+    var_dump(func_get_args());
+    $b = 10;
+    $c = 11;
+    return array($b,$c);
+}
+
+function aop_foo_ref($a,&$b,&$c)
+{
+    $args = \pinpoint_get_func_ref_args();
+    return call_user_func_array('foo_ref',$args);
+}
+$b =2;
+$c = 12;
+var_dump(aop_foo_ref("adf",$b,$c));
+echo "b = $b \n";
+echo "c = $c \n";
+
+--EXPECTF--
+array(4) {
+  [0]=>
+  &int(100)
+  [1]=>
+  int(1)
+  [2]=>
+  int(3)
+  [3]=>
+  int(4)
+}
+string(12) "hello php!!!"
+
+Warning: pinpoint_get_func_ref_args():  Called from the global scope - no function context in %s on line 18
+bool(false)
+call __construct 
+array(2) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+}
+array(3) {
+  [0]=>
+  string(14) "hello pinpoint"
+  [1]=>
+  int(1)
+  [2]=>
+  array(3) {
+    [1]=>
+    int(2)
+    ["c"]=>
+    int(3)
+    ["e"]=>
+    int(5)
+  }
+}
+array(3) {
+  [0]=>
+  string(14) "hello pinpoint"
+  [1]=>
+  int(1)
+  [2]=>
+  array(3) {
+    [1]=>
+    int(2)
+    ["c"]=>
+    int(3)
+    ["e"]=>
+    int(5)
+  }
+}
+array(0) {
+}
+array(3) {
+  [0]=>
+  string(2) "23"
+  [1]=>
+  int(1)
+  [2]=>
+  NULL
+}
+test anonymous 
+array(1) {
+  [0]=>
+  string(6) "hello "
+}
+array(1) {
+  [0]=>
+  string(14) "hello eeliu-01"
+}
+
+test pinpoint_get_func_ref_args call in call_user_func_array 
+array(3) {
+  [0]=>
+  string(3) "adf"
+  [1]=>
+  int(2)
+  [2]=>
+  int(12)
+}
+array(2) {
+  [0]=>
+  int(10)
+  [1]=>
+  int(11)
+}
+b = 10 
+c = 11 
+call __destruct 
+array(0) {
+}
\ No newline at end of file
diff --git a/tests_win32/app_info_test.phpt b/tests_win32/app_info_test.phpt
new file mode 100644
index 00000000..7c7e1817
--- /dev/null
+++ b/tests_win32/app_info_test.phpt
@@ -0,0 +1,16 @@
+--TEST--
+app info 
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+var_dump(_pinpoint_start_time());
+var_dump("APP".'^'.strval(_pinpoint_start_time()).'^'.strval(_pinpoint_unique_id()));
+--EXPECTF--
+float(%d)
+string(%d) "APP^%d^%d"
\ No newline at end of file
diff --git a/tests_win32/drop_trace_test.phpt b/tests_win32/drop_trace_test.phpt
new file mode 100644
index 00000000..68da7e59
--- /dev/null
+++ b/tests_win32/drop_trace_test.phpt
@@ -0,0 +1,23 @@
+--TEST--
+drop this trace
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+_pinpoint_start_trace();
+_pinpoint_drop_trace();
+_pinpoint_add_clue("args",'a,$b');
+_pinpoint_add_clue("ret",'a,$b');
+_pinpoint_end_trace();
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d]change current [128] status, before:2,now:4
+[pinpoint] [%d] [%d] [128] add clue key:args value:a,$b
+[pinpoint] [%d] [%d] [128] add clue key:ret value:a,$b
+[pinpoint] [%d] [%d]current [128] span dropped,due to TRACE_BLOCK
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
\ No newline at end of file
diff --git a/tests_win32/mark_as_error.phpt b/tests_win32/mark_as_error.phpt
new file mode 100644
index 00000000..b47e4b91
--- /dev/null
+++ b/tests_win32/mark_as_error.phpt
@@ -0,0 +1,26 @@
+--TEST--
+pinpoint_php internal test case [pinpoint_test_main]
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+_pinpoint_start_trace();
+_pinpoint_add_clue("args",'a,$b');
+_pinpoint_add_clue("ret",'a,$b');
+_pinpoint_mark_as_error("message you cared","filename you cared",1023);
+echo _pinpoint_end_trace()."\n";
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] add clue key:args value:a,$b
+[pinpoint] [%d] [%d] [128] add clue key:ret value:a,$b
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"ERR":{"file":"filename you cared","line":1023,"msg":"message you cared"},"args":"a,$b","ret":"a,$b"})
+[pinpoint] [%d] [%d]agent try to connect:(localhost:10000)
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+0
\ No newline at end of file
diff --git a/tests_win32/node_test.phpt b/tests_win32/node_test.phpt
new file mode 100644
index 00000000..24ac0276
--- /dev/null
+++ b/tests_win32/node_test.phpt
@@ -0,0 +1,35 @@
+--TEST--
+Test pinpoint_unique_id
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+
+$unexist_node = 1024;
+
+_pinpoint_start_trace($unexist_node);
+
+_pinpoint_add_clue("adf","fdfd",$unexist_node,0);
+_pinpoint_add_clue("adf","fdfd",$unexist_node,1);
+_pinpoint_set_context('b','b',$unexist_node);
+_pinpoint_add_clues(32,"fdfd",$unexist_node,1);
+_pinpoint_add_clues(32,"fdfd",$unexist_node,0);
+
+_pinpoint_get_context('b',$unexist_node);
+
+_pinpoint_end_trace($unexist_node);
+
+--EXPECTF--
+[pinpoint] [%d] [%d] start_trace [1024] failed with #1024 is not alive
+[pinpoint] [%d] [%d] pinpoint_add_clue [1024] failed. Reason: #1024 is not alive,parameters:adf:fdfd
+[pinpoint] [%d] [%d] pinpoint_add_clue [1024] failed. Reason: #1024 is not alive,parameters:adf:fdfd
+[pinpoint] [%d] [%d] pinpoint_set_context_key [1024] failed with out_of_range. #1024 is not alive,parameters:b:b
+[pinpoint] [%d] [%d] pinpoint_add_clues [1024] failed. Reason #1024 is not alive,parameters:32:fdfd
+[pinpoint] [%d] [%d] pinpoint_add_clues [1024] failed. Reason #1024 is not alive,parameters:32:fdfd
+[pinpoint] [%d] [%d] pinpoint_get_context_key [1024] failed with #1024 is not alive, parameters:b
+[pinpoint] [%d] [%d]end_trace 1024 out_of_range exception: #1024 is not alive
\ No newline at end of file
diff --git a/tests_win32/pinpoint_get_caller_arg.phpt b/tests_win32/pinpoint_get_caller_arg.phpt
new file mode 100644
index 00000000..9dfb10dd
--- /dev/null
+++ b/tests_win32/pinpoint_get_caller_arg.phpt
@@ -0,0 +1,63 @@
+--TEST--
+pinpoint_php test  pinpoint_get_caller_arg
+--SKIPIF--
+<?php 
+if (!extension_loaded("pinpoint_php")) 
+{   
+    print "skip"; 
+    print "pinpoint_php"; 
+}
+if (!extension_loaded("curl")) 
+{   
+    print "skip"; 
+    print "curl"; 
+}
+
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+curl
+--FILE--
+<?php
+
+_pinpoint_join_cut(
+    ["curl_exec"],
+    function ($a) {
+    },
+    function ($ret) {
+        $ch = pinpoint_get_caller_arg(0);
+        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+        echo "status_code $code \n";
+    },
+    function ($e) {
+    }
+);
+
+echo "case: curl_init() \n";
+
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, "http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:"xxxx"',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+
+$j_res = json_decode($response, true);
+
+$error = curl_error($ch);
+echo "error: $error\n";
+curl_close($ch);
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor function=curl_exec
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_exec success
+case: curl_init() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+status_code 200 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+[pinpoint] [%d] [%d]start free interceptor: curl_exec
\ No newline at end of file
diff --git a/tests_win32/pinpoint_get_this.phpt b/tests_win32/pinpoint_get_this.phpt
new file mode 100644
index 00000000..babd5089
--- /dev/null
+++ b/tests_win32/pinpoint_get_this.phpt
@@ -0,0 +1,61 @@
+--TEST--
+pinpoint_php test get this
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+
+class Foo{
+    public function output(){
+
+      $onBefore = function(){
+        $f = pinpoint_get_this();
+        if($f instanceof  Foo){
+          var_dump($f->abc);
+          var_dump($f->abc_s);
+          echo " update foo members \n";
+          $f->abc = 1234;
+          $f->abc_s= "hello pinpoint";
+        }
+      };
+
+      $onBefore();
+    }
+    public $abc = 123;
+    public $abc_s = "123";
+}
+
+$f = new Foo();
+$f->output();
+var_dump($f->abc);
+var_dump($f->abc_s);
+var_dump(pinpoint_get_this());
+
+echo "test static method \n";
+class S_Foo
+{
+    public static $my_static = 'foo';
+
+    public static function staticValue() {
+      $f = pinpoint_get_this();
+      var_dump($f);
+      return self::$my_static;
+    }
+}
+
+$sf = new S_Foo();
+S_Foo::staticValue();
+
+--EXPECTF--
+int(123)
+string(3) "123"
+ update foo members 
+int(1234)
+string(14) "hello pinpoint"
+[pinpoint] [%d] [%d]pinpoint_get_this: not support, no this
+bool(false)
+test static method 
+[pinpoint] [%d] [%d]pinpoint_get_this: not support, no this
+bool(false)
\ No newline at end of file
diff --git a/tests_win32/pinpoint_join_cut_curl_7.phpt b/tests_win32/pinpoint_join_cut_curl_7.phpt
new file mode 100644
index 00000000..72ef024d
--- /dev/null
+++ b/tests_win32/pinpoint_join_cut_curl_7.phpt
@@ -0,0 +1,233 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_cut
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("curl"))
+   print "skip";
+if (version_compare(phpversion(), '8.0.0', '>='))
+{    print "skip";
+    print "only works in php7";
+}
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}
+?>
+--INI--
+pinpoint_php.DebugReport=true
+
+--EXTENSIONS--
+json
+curl
+
+--FILE--
+<?php
+_pinpoint_join_cut(
+    ["curl_init"],
+    function ($a = null) {
+        echo "on_before \n";
+        var_dump($a);
+    },
+    function ($ret) {
+        echo "on_end \n";
+        var_dump($ret);
+        if (is_resource($ret)) {
+            echo "get resource ";
+            assert(curl_setopt($ret, CURLOPT_HEADER, false));
+        }
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    }
+);
+
+_pinpoint_join_cut(
+    ["curl_exec"],
+    function ($a) {
+        echo "on_before \n";
+        var_dump($a);
+        assert(is_resource($a));
+        echo "request url: " . curl_getinfo($a, CURLINFO_EFFECTIVE_URL) . "\n";
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    }
+);
+
+_pinpoint_join_cut(
+    ["curl_setopt"],
+    function ($ch, $option, $value) {
+        assert(is_resource($ch));
+        var_dump($option);
+
+        if ($option == CURLOPT_HTTPHEADER && is_array($value)) {
+            $value[] = "pinpoint_join_cut:xxxx";
+            $value[] = "pinpoint_join_cu2t:agc";
+            $value[] = "pinpoint_join_cus2t:agc";
+            $value[] = "pinpoint_join_cus2t2:agc";
+            echo "value must be affected\n";
+            return [$ch, $option, $value];
+        } else if ($option == CURLOPT_RETURNTRANSFER && is_bool($value)) {
+            echo "test CURLOPT_RETURNTRANSFER \n";
+            return [$ch, $option, 2];
+        } else if ($option == CURLOPT_URL && is_string($value)) {
+            echo "test CURLOPT_URL \n";
+            return [$ch, 2];
+        } else {
+            echo "not working";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    }
+);
+
+
+echo "case: curl_init() \n";
+
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, "http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:"xxxx"',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+
+$j_res = json_decode($response, true);
+
+assert($j_res["headers"]["Pinpoint-Join-Cu2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T2"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cut"] == "xxxx");
+
+$error = curl_error($ch);
+echo "error:$error \n";
+curl_close($ch);
+
+echo "case : curl_init with variable \n";
+$ch = curl_init("http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:"xxxx"',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+$j_res = json_decode($response, true);
+
+assert($j_res["headers"]["Pinpoint-Join-Cu2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T2"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cut"] == "xxxx");
+$error = curl_error($ch);
+echo "error:$error \n";
+curl_close($ch);
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor function=curl_init
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_init success
+[pinpoint] [%d] [%d]try to interceptor function=curl_exec
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_exec success
+[pinpoint] [%d] [%d]try to interceptor function=curl_setopt
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_setopt success
+case: curl_init() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_init
+on_before 
+NULL
+[pinpoint] [%d] [%d] call_interceptor_before:curl_init return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+resource(4) of type (curl)
+get resource [pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(42)
+not working[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_init 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10002)
+test CURLOPT_URL 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:2
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `size` does not matched
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(19913)
+test CURLOPT_RETURNTRANSFER 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `type` does not matched expected:3 give:4
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10023)
+value must be affected
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]args[2] type:7 in:1 va:2
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+on_before 
+resource(4) of type (curl)
+request url: http://httpbin.org/anything
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+case : curl_init with variable 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_init
+on_before 
+string(27) "http://httpbin.org/anything"
+[pinpoint] [%d] [%d] call_interceptor_before:curl_init return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+resource(5) of type (curl)
+get resource [pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(42)
+not working[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_init 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(19913)
+test CURLOPT_RETURNTRANSFER 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `type` does not matched expected:3 give:4
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10023)
+value must be affected
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]args[2] type:7 in:1 va:2
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+on_before 
+resource(5) of type (curl)
+request url: http://httpbin.org/anything
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+[pinpoint] [%d] [%d]start free interceptor: curl_init
+[pinpoint] [%d] [%d]start free interceptor: curl_exec
+[pinpoint] [%d] [%d]start free interceptor: curl_setopt
\ No newline at end of file
diff --git a/tests_win32/pinpoint_join_cut_curl_8.phpt b/tests_win32/pinpoint_join_cut_curl_8.phpt
new file mode 100644
index 00000000..ba1726d1
--- /dev/null
+++ b/tests_win32/pinpoint_join_cut_curl_8.phpt
@@ -0,0 +1,234 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_cut
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("curl"))
+   print "skip no curl";
+if (version_compare(phpversion(), '8.0.0', '<')){   
+    print "skip only works in php8";
+}
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}
+?>
+--INI--
+pinpoint_php.DebugReport=true
+
+--EXTENSIONS--
+json
+
+--FILE--
+<?php
+_pinpoint_join_cut(
+    ["curl_init"],
+    function ($a = null) {
+        echo "on_before \n";
+        var_dump($a);
+    },
+    function ($ret) {
+        echo "on_end \n";
+        var_dump($ret);
+        if ($ret instanceof CurlHandle) {
+            echo "get resource ";
+            assert(curl_setopt($ret, CURLOPT_HEADER, false));
+        }
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    },
+);
+
+_pinpoint_join_cut(
+    ["curl_exec"],
+    function ($a) {
+        echo "on_before \n";
+        var_dump($a);
+        assert($a instanceof CurlHandle);
+        echo "request url: " . curl_getinfo($a, CURLINFO_EFFECTIVE_URL) . "\n";
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    },
+);
+
+_pinpoint_join_cut(
+    ["curl_setopt"],
+    function ($ch, $option, $value) {
+        assert($ch instanceof CurlHandle);
+        var_dump($option);
+
+        if ($option == CURLOPT_HTTPHEADER && is_array($value)) {
+            $value[] = "pinpoint_join_cut:xxxx";
+            $value[] = "pinpoint_join_cu2t:agc";
+            $value[] = "pinpoint_join_cus2t:agc";
+            $value[] = "pinpoint_join_cus2t2:agc";
+            echo "value must be affected\n";
+            return [$ch, $option, $value];
+        } else if ($option == CURLOPT_RETURNTRANSFER && is_bool($value)) {
+            echo "test CURLOPT_RETURNTRANSFER \n";
+            return [$ch, $option, 2];
+        } else if ($option == CURLOPT_URL && is_string($value)) {
+            echo "test CURLOPT_URL \n";
+            return [$ch, 2];
+        } else {
+            echo "not working";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+        var_dump($e);
+    },
+);
+
+
+echo "case: curl_init() \n";
+
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, "http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:xxxx',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+
+$j_res = json_decode($response, true);
+assert($j_res["headers"]["Pinpoint-Join-Cu2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T2"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cut"] == "xxxx");
+
+$error = curl_error($ch);
+echo "error:$error \n";
+curl_close($ch);
+
+echo "case : curl_init with variable \n";
+$ch = curl_init("http://httpbin.org/anything");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    'user_header:"xxxx"',
+    'user_abc:2133'
+]);
+$response = curl_exec($ch);
+$j_res = json_decode($response, true);
+
+assert($j_res["headers"]["Pinpoint-Join-Cu2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cus2T2"] == "agc");
+assert($j_res["headers"]["Pinpoint-Join-Cut"] == "xxxx");
+$error = curl_error($ch);
+echo "error:$error \n";
+curl_close($ch);
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor function=curl_init
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_init success
+[pinpoint] [%d] [%d]try to interceptor function=curl_exec
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_exec success
+[pinpoint] [%d] [%d]try to interceptor function=curl_setopt
+[pinpoint] [%d] [%d]added interceptor on `function`: curl_setopt success
+case: curl_init() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_init
+on_before 
+NULL
+[pinpoint] [%d] [%d] call_interceptor_before:curl_init return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+object(CurlHandle)#10 (0) {
+}
+get resource [pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(42)
+not working[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_init 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10002)
+test CURLOPT_URL 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:2
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `size` does not matched
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(19913)
+test CURLOPT_RETURNTRANSFER 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `type` does not matched expected:3 give:4
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10023)
+value must be affected
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]args[2] type:7 in:1 va:2
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+on_before 
+object(CurlHandle)#10 (0) {
+}
+request url: http://httpbin.org/anything
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+case : curl_init with variable 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_init
+on_before 
+string(27) "http://httpbin.org/anything"
+[pinpoint] [%d] [%d] call_interceptor_before:curl_init return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+object(CurlHandle)#11 (0) {
+}
+get resource [pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(42)
+not working[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_init 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(19913)
+test CURLOPT_RETURNTRANSFER 
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]error: replace_ex_caller_parameters return `type` does not matched expected:3 give:4
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_setopt
+int(10023)
+value must be affected
+[pinpoint] [%d] [%d] call_interceptor_before:curl_setopt return type(7) zval
+[pinpoint] [%d] [%d]argv size:3
+[pinpoint] [%d] [%d]args[2] type:7 in:1 va:2
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_setopt 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:curl_exec
+on_before 
+object(CurlHandle)#11 (0) {
+}
+request url: http://httpbin.org/anything
+[pinpoint] [%d] [%d] call_interceptor_before:curl_exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: curl_exec 
+error: 
+[pinpoint] [%d] [%d]start free interceptor: curl_init
+[pinpoint] [%d] [%d]start free interceptor: curl_exec
+[pinpoint] [%d] [%d]start free interceptor: curl_setopt
\ No newline at end of file
diff --git a/tests_win32/pinpoint_join_cut_extend_pdo.phpt b/tests_win32/pinpoint_join_cut_extend_pdo.phpt
new file mode 100644
index 00000000..d1c61f04
--- /dev/null
+++ b/tests_win32/pinpoint_join_cut_extend_pdo.phpt
@@ -0,0 +1,156 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_pdo
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("pdo"))
+  print "skip";
+if (version_compare(phpversion(), '8.2.0', '>=')){
+  print "skip";
+  print phpversion() . ">= 8.2.0";
+}
+
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}
+
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+pdo_mysql
+--FILE--
+<?php
+
+_pinpoint_join_cut(
+    ["PDO", "__construct"],
+    function ($dsn, $username = null, $password = null, $options = null) {
+        echo "on_before: $dsn \n";
+        $pdo = pinpoint_get_this();
+        if ($pdo instanceof PDO) {
+            $pdo->dsn = $dsn;
+            echo "attached dsn \n";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+    }
+);
+
+$pdo_exec = "PDO::exec";
+_pinpoint_join_cut(
+    ["PDO", "exec"],
+    function ($statement) use ($pdo_exec) {
+        echo "$pdo_exec: on_before: $statement \n";
+    },
+    function ($ret) use ($pdo_exec) {
+        echo "$pdo_exec : on_end \n";
+    },
+    function ($e) use ($pdo_exec) {
+        echo "on_exception \n";
+    }
+);
+
+class MyPDO extends PDO
+{
+
+}
+$dbname = "employees";
+$pdo = new MyPDO("mysql:host=dev-mysql;dbname=$dbname", 'root', 'password');
+$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+$pdo->abc = "123";
+$sql = "CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' );";
+$ret = $pdo->exec($sql);
+if ($ret === false) {
+    echo "create pdo_test failed" . $pdo->errorCode();
+}
+
+$sql = "INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1);";
+$ret = $pdo->exec($sql);
+var_dump($ret);
+
+$unbufferedResult = $pdo->query("SELECT * FROM pdo_test");
+foreach ($unbufferedResult as $row) {
+    var_dump($unbufferedResult);
+}
+
+$sth = $pdo->prepare('SELECT name FROM pdo_test
+    WHERE AGE = :AGE limit 3');
+/* Names can be prefixed with colons ":" too (optional) */
+$sth->bindValue(':AGE', 1);
+$ret = $sth->execute();
+var_dump($ret);
+$ret = $sth->fetch();
+var_dump($ret);
+$ret = $sth->fetchAll();
+var_dump($ret);
+var_dump($pdo->abc);
+var_dump($pdo->dsn);
+$sql = 'DROP TABLE pdo_test';
+$ret = $pdo->exec($sql);
+
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:__construct
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::__construct success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:exec
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::exec success
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::__construct
+on_before: mysql:host=dev-mysql;dbname=employees 
+attached dsn 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::__construct return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::__construct 
+int(4)
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+bool(true)
+array(2) {
+  ["name"]=>
+  string(1) "a"
+  [0]=>
+  string(1) "a"
+}
+array(2) {
+  [0]=>
+  array(2) {
+    ["name"]=>
+    string(1) "b"
+    [0]=>
+    string(1) "b"
+  }
+  [1]=>
+  array(2) {
+    ["name"]=>
+    string(1) "d"
+    [0]=>
+    string(1) "d"
+  }
+}
+string(3) "123"
+string(37) "mysql:host=dev-mysql;dbname=employees"
+[pinpoint] [%d] [%d]start free interceptor: pdo::__construct
+[pinpoint] [%d] [%d]start free interceptor: pdo::exec
\ No newline at end of file
diff --git a/tests_win32/pinpoint_join_cut_mysqli.phpt b/tests_win32/pinpoint_join_cut_mysqli.phpt
new file mode 100644
index 00000000..f57d505d
--- /dev/null
+++ b/tests_win32/pinpoint_join_cut_mysqli.phpt
@@ -0,0 +1,90 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_mysqli
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}  
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+mysqli
+--FILE--
+
+<?php
+
+$on_before = function (...$args) {
+    $mysqli = pinpoint_get_this();
+    $db_host = "localhost";
+    if ($mysqli instanceof mysqli) {
+        $db_host = $mysqli->host_info;
+    }
+    echo "$db_host \n";
+};
+
+$on_before_func = function (...$args) {
+    $mysqli = $args[0];
+    $db_host = "localhost";
+    if ($mysqli instanceof mysqli) {
+        $db_host = $mysqli->host_info;
+    }
+    echo "$db_host \n";
+};
+
+$on_end = function ($ret) {
+
+};
+
+$on_exception = function ($exp) {
+};
+
+
+_pinpoint_join_cut(['mysqli_query'], $on_before_func, $on_end, $on_exception);
+_pinpoint_join_cut(['mysqli', 'query'], $on_before, $on_end, $on_exception);
+
+
+
+mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
+$mysqli = new mysqli();
+
+$mysqli->connect('dev-mysql', "root", "password", "employees", 3306);
+
+$result = $mysqli->query("SELECT * FROM `dept_emp_latest_date` LIMIT 1000;");
+printf("Select returned %d rows.\n", $result->num_rows);
+
+$stmt = $mysqli->prepare("SELECT * FROM employees WHERE emp_no=?");
+$id = 10005;
+$stmt->bind_param("i", $id);
+$stmt->execute();
+$stmt->fetch();
+$stmt->free_result();
+mysqli_query($mysqli, "SELECT * FROM `dept_emp_latest_date` LIMIT 1000;");
+
+$s_stmt = mysqli_prepare($mysqli, "SELECT * FROM employees WHERE emp_no=?");
+mysqli_stmt_bind_param($s_stmt, "i", $id);
+mysqli_stmt_execute($stmt);
+
+
+
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor function=mysqli_query
+[pinpoint] [%d] [%d]added interceptor on `function`: mysqli_query success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=mysqli:query
+[pinpoint] [%d] [%d]added interceptor on `module`: mysqli::query success
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:mysqli::query
+dev-mysql via TCP/IP 
+[pinpoint] [%d] [%d] call_interceptor_before:mysqli::query return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+[pinpoint] [%d] [%d]call_interceptor_end: mysqli::query 
+Select returned 1000 rows.
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:mysqli_query
+dev-mysql via TCP/IP 
+[pinpoint] [%d] [%d] call_interceptor_before:mysqli_query return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+[pinpoint] [%d] [%d]call_interceptor_end: mysqli_query 
+[pinpoint] [%d] [%d]start free interceptor: mysqli_query
+[pinpoint] [%d] [%d]start free interceptor: mysqli::query
\ No newline at end of file
diff --git a/tests_win32/pinpoint_join_cut_pdo.phpt b/tests_win32/pinpoint_join_cut_pdo.phpt
new file mode 100644
index 00000000..385f7dd9
--- /dev/null
+++ b/tests_win32/pinpoint_join_cut_pdo.phpt
@@ -0,0 +1,176 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_pdo
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("pdo"))
+  print "skip";
+if (version_compare(phpversion(), '8.2.0', '>=')){
+  print "skip";
+  print phpversion() . ">= 8.2.0";
+}
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}
+   
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+pdo_mysql
+--FILE--
+<?php
+
+_pinpoint_join_cut(
+    ["PDO", "__construct"],
+    function ($dsn, $username = null, $password = null, $options = null) {
+        echo "on_before: $dsn \n";
+        $pdo = pinpoint_get_this();
+        if ($pdo instanceof PDO) {
+            $pdo->dsn = $dsn;
+            echo "attached dsn \n";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+    }
+);
+$pdo_exec = "PDO::exec";
+_pinpoint_join_cut(
+    ["PDO", "exec"],
+    function ($statement) use ($pdo_exec) {
+        echo "$pdo_exec: on_before: $statement \n";
+    },
+    function ($ret) use ($pdo_exec) {
+        echo "$pdo_exec : on_end \n";
+    },
+    function ($e) use ($pdo_exec) {
+        echo "on_exception \n";
+    }
+);
+
+
+echo "case: pdo() \n";
+
+$dbname = "employees";
+$pdo = new PDO("mysql:host=dev-mysql;dbname=$dbname", 'root', 'password');
+$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+$pdo->abc = "123";
+$sql = "CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' );";
+$ret = $pdo->exec($sql);
+if ($ret === false) {
+    echo "create pdo_test failed" . $pdo->errorCode();
+}
+
+$sql = "INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1);";
+$ret = $pdo->exec($sql);
+var_dump($ret);
+
+$unbufferedResult = $pdo->query("SELECT * FROM pdo_test");
+foreach ($unbufferedResult as $row) {
+    var_dump($unbufferedResult);
+}
+
+$sth = $pdo->prepare('SELECT name FROM pdo_test
+    WHERE AGE = :AGE limit 3');
+/* Names can be prefixed with colons ":" too (optional) */
+$sth->bindValue(':AGE', 1);
+$ret = $sth->execute();
+var_dump($ret);
+$ret = $sth->fetch();
+var_dump($ret);
+$ret = $sth->fetchAll();
+var_dump($ret);
+var_dump($pdo->abc);
+var_dump($pdo->dsn);
+$sql = 'DROP TABLE pdo_test';
+$ret = $pdo->exec($sql);
+
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:__construct
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::__construct success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:exec
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::exec success
+case: pdo() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::__construct
+on_before: mysql:host=dev-mysql;dbname=employees 
+attached dsn 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::__construct return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::__construct 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' ); 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1); 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+int(4)
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#8 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+bool(true)
+array(2) {
+  ["name"]=>
+  string(1) "a"
+  [0]=>
+  string(1) "a"
+}
+array(2) {
+  [0]=>
+  array(2) {
+    ["name"]=>
+    string(1) "b"
+    [0]=>
+    string(1) "b"
+  }
+  [1]=>
+  array(2) {
+    ["name"]=>
+    string(1) "d"
+    [0]=>
+    string(1) "d"
+  }
+}
+string(3) "123"
+string(37) "mysql:host=dev-mysql;dbname=employees"
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: DROP TABLE pdo_test 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+[pinpoint] [%d] [%d]start free interceptor: pdo::__construct
+[pinpoint] [%d] [%d]start free interceptor: pdo::exec
\ No newline at end of file
diff --git a/tests_win32/pinpoint_join_cut_pdo_8.phpt b/tests_win32/pinpoint_join_cut_pdo_8.phpt
new file mode 100644
index 00000000..5c569de6
--- /dev/null
+++ b/tests_win32/pinpoint_join_cut_pdo_8.phpt
@@ -0,0 +1,187 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_pdo_8
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+if (!extension_loaded("pdo"))
+  print "skip";
+if (version_compare(phpversion(), '8.2.0', '<'))
+{   
+    print "skip";
+  print phpversion() ."< 8.2.0";
+}
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+pdo_mysql
+
+--FILE--
+<?php
+
+$weakMap = new WeakMap();
+
+_pinpoint_join_cut(
+    ["PDO", "__construct"],
+    function ($dsn, $username = null, $password = null, $options = null) use ($weakMap) {
+        echo "on_before: $dsn \n";
+        $pdo = pinpoint_get_this();
+        if ($pdo instanceof PDO) {
+            $weakMap[$pdo] = $dsn;
+            echo "attached dsn \n";
+        }
+    },
+    function ($ret) {
+        echo "on_end \n";
+    },
+    function ($e) {
+        echo "on_exception \n";
+    }
+);
+$pdo_exec = "PDO::exec";
+_pinpoint_join_cut(
+    ["PDO", "exec"],
+    function ($statement) use ($pdo_exec, $weakMap) {
+
+        echo "$pdo_exec: on_before: $statement \n";
+
+        $pdo = pinpoint_get_this();
+        if ($pdo instanceof PDO) {
+            echo "$weakMap[$pdo] \n";
+        }
+
+    },
+    function ($ret) use ($pdo_exec) {
+        echo "$pdo_exec : on_end \n";
+    },
+    function ($e) use ($pdo_exec) {
+        echo "on_exception \n";
+    }
+);
+
+
+echo "case: pdo() \n";
+
+$dbname = "employees";
+$pdo = new PDO("mysql:host=dev-mysql;dbname=$dbname", 'root', 'password');
+$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+$sql = "CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' );";
+$ret = $pdo->exec($sql);
+if ($ret === false) {
+    echo "create pdo_test failed" . $pdo->errorCode();
+}
+
+$sql = "INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1);";
+$ret = $pdo->exec($sql);
+var_dump($ret);
+
+$unbufferedResult = $pdo->query("SELECT * FROM pdo_test");
+foreach ($unbufferedResult as $row) {
+    var_dump($unbufferedResult);
+}
+
+$sth = $pdo->prepare('SELECT name FROM pdo_test
+    WHERE AGE = :AGE limit 3');
+/* Names can be prefixed with colons ":" too (optional) */
+$sth->bindValue(':AGE', 1);
+$ret = $sth->execute();
+var_dump($ret);
+$ret = $sth->fetch();
+var_dump($ret);
+$ret = $sth->fetchAll();
+var_dump($ret);
+var_dump($weakMap[$pdo]);
+$sql = 'DROP TABLE pdo_test';
+$ret = $pdo->exec($sql);
+
+
+
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:__construct
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::__construct success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=pdo:exec
+[pinpoint] [%d] [%d]added interceptor on `module`: pdo::exec success
+case: pdo() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::__construct
+on_before: mysql:host=dev-mysql;dbname=employees 
+attached dsn 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::__construct return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::__construct 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: CREATE table IF NOT EXISTS pdo_test(
+     ID INT( 11 ) AUTO_INCREMENT PRIMARY KEY,
+     Name VARCHAR( 250 ) NOT NULL,
+     AGE tinyint(1) unsigned NOT NULL default '1' ); 
+mysql:host=dev-mysql;dbname=employees 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: INSERT INTO pdo_test (NAME, AGE)
+VALUES ('a',1),('b',1),('c',3),('d',1); 
+mysql:host=dev-mysql;dbname=employees 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+int(4)
+object(PDOStatement)#9 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#9 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#9 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+object(PDOStatement)#9 (1) {
+  ["queryString"]=>
+  string(22) "SELECT * FROM pdo_test"
+}
+bool(true)
+array(2) {
+  ["name"]=>
+  string(1) "a"
+  [0]=>
+  string(1) "a"
+}
+array(2) {
+  [0]=>
+  array(2) {
+    ["name"]=>
+    string(1) "b"
+    [0]=>
+    string(1) "b"
+  }
+  [1]=>
+  array(2) {
+    ["name"]=>
+    string(1) "d"
+    [0]=>
+    string(1) "d"
+  }
+}
+string(37) "mysql:host=dev-mysql;dbname=employees"
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:pdo::exec
+PDO::exec: on_before: DROP TABLE pdo_test 
+mysql:host=dev-mysql;dbname=employees 
+[pinpoint] [%d] [%d] call_interceptor_before:pdo::exec return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+PDO::exec : on_end 
+[pinpoint] [%d] [%d]call_interceptor_end: pdo::exec 
+[pinpoint] [%d] [%d]start free interceptor: pdo::__construct
+[pinpoint] [%d] [%d]start free interceptor: pdo::exec
\ No newline at end of file
diff --git a/tests_win32/pinpoint_join_cut_redis.phpt b/tests_win32/pinpoint_join_cut_redis.phpt
new file mode 100644
index 00000000..2ec54f32
--- /dev/null
+++ b/tests_win32/pinpoint_join_cut_redis.phpt
@@ -0,0 +1,296 @@
+--TEST--
+pinpoint_php pinpoint_join_cut_redis
+--SKIPIF--
+<?php
+if (!extension_loaded("pinpoint_php"))
+  print "skip";
+
+if (!extension_loaded("redis"))
+  print "skip";
+
+if (version_compare(phpversion(), '7.1.33', '<='))
+   print "skip";
+
+if(getenv('SKIP_WINDOWS_ACTION', true)){
+  print "skip";
+}
+?>
+--INI--
+pinpoint_php.DebugReport=true
+--EXTENSIONS--
+redis
+json
+--FILE--
+<?php
+function make_method_plugins_var_2($class_name, $method_name)
+{
+    //  connect 
+    $interceptor_name = "$class_name::$method_name";
+    $on_before_2 = function ($key, $value) use ($interceptor_name) {
+        echo "$interceptor_name before: $key : $value \n";
+    };
+
+    $on_end = function ($ret) use ($interceptor_name) {
+        echo "$interceptor_name end \n";
+    };
+
+    $on_exception = function ($exp) use ($interceptor_name) {
+        echo "$interceptor_name exception \n";
+    };
+
+    return [$class_name, $method_name, $on_before_2, $on_end, $on_exception];
+}
+
+function make_method_plugins_var_1($class_name, $method_name)
+{
+    $interceptor_name = "$class_name::$method_name";
+
+    $on_before_1 = function ($key = null) use ($interceptor_name) {
+        echo "$interceptor_name before: $key \n";
+    };
+
+    $on_end = function ($ret) use ($interceptor_name) {
+        echo "$interceptor_name end \n";
+    };
+
+    $on_exception = function ($exp) use ($interceptor_name) {
+        echo "$interceptor_name exception \n";
+    };
+
+    return [$class_name, $method_name, $on_before_1, $on_end, $on_exception];
+}
+
+function make_method_plugins_var_3($class_name, $method_name)
+{
+    $interceptor_name = "$class_name::$method_name";
+
+    $on_before_1 = function ($key, $_1, $_2) use ($interceptor_name) {
+        echo "$interceptor_name before: $key \n";
+    };
+
+    $on_end = function ($ret) use ($interceptor_name) {
+        echo "$interceptor_name end \n";
+    };
+
+    $on_exception = function ($exp) use ($interceptor_name) {
+        echo "$interceptor_name exception \n";
+    };
+
+    return [$class_name, $method_name, $on_before_1, $on_end, $on_exception];
+}
+
+
+function make_method_plugins_var_ar($class_name, $method_name)
+{
+    $interceptor_name = "$class_name::$method_name";
+
+    $on_before_1 = function ($ar) use ($interceptor_name) {
+        echo "$interceptor_name before:  \n";
+    };
+
+    $on_end = function ($ret) use ($interceptor_name) {
+        echo "$interceptor_name end \n";
+    };
+
+    $on_exception = function ($exp) use ($interceptor_name) {
+        echo "$interceptor_name exception \n";
+    };
+
+    return [$class_name, $method_name, $on_before_1, $on_end, $on_exception];
+}
+
+$points = [
+    make_method_plugins_var_1("Redis", "info"),
+    make_method_plugins_var_1("Redis", "get"),
+    make_method_plugins_var_2("Redis", "set"),
+    make_method_plugins_var_2("Redis", "setNx"),
+    make_method_plugins_var_2("Redis", "append"),
+    make_method_plugins_var_3("Redis", "getRange"),
+    make_method_plugins_var_3("Redis", "setRange"),
+    make_method_plugins_var_1("Redis", "strlen"),
+    make_method_plugins_var_2("Redis", "getBit"),
+    make_method_plugins_var_3("Redis", "setBit"),
+    make_method_plugins_var_ar("Redis", "mSet"),
+    make_method_plugins_var_ar("Redis", "mSetNx"),
+];
+
+foreach ($points as $point) {
+    _pinpoint_join_cut(
+        [$point[0], $point[1]],
+        $point[2],
+        $point[3],
+        $point[4]
+    );
+}
+
+
+
+echo "case: redis(xxx) \n";
+
+$redis = new Redis([
+    'host' => 'redis',
+    'port' => 6379,
+    'connectTimeout' => 2.5
+]);
+assert($redis->info() !== false);
+
+echo "case: redis() \n";
+$redis = new Redis();
+$redis->connect('redis', 6379);
+assert($redis->info() !== false);
+
+echo "case: redis() \n";
+$redis = new Redis();
+$redis->pconnect('redis', 6379);
+assert($redis->info() !== false);
+
+echo "case: strings \n";
+$redis = new Redis();
+$redis->pconnect('redis', 6379);
+$redis->get("a");
+$redis->set("a", "b");
+$redis->setNx("a", "10");
+$redis->append("ar", "aa");
+$redis->setRange("ar", 0, "bb");
+$redis->get("ar");
+$redis->getRange("ar", 0, 2);
+$redis->strlen("ar");
+$redis->getBit("ar", 1);
+$redis->setBit("ar", 1, 3);
+var_dump($redis->get("ar"));
+$redis->mSet(['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz']);
+var_dump($redis->exists('foo', 'bar', 'baz', 'not exists')); 
+$redis->flushdb();
+--EXPECTF--
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:info
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::info success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:get
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::get success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:set
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::set success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:setnx
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::setnx success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:append
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::append success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:getrange
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::getrange success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:setrange
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::setrange success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:strlen
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::strlen success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:getbit
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::getbit success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:setbit
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::setbit success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:mset
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::mset success
+[pinpoint] [%d] [%d]try to interceptor module(class)/function=redis:msetnx
+[pinpoint] [%d] [%d]added interceptor on `module`: redis::msetnx success
+case: redis(xxx) 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::info
+Redis::info before:  
+[pinpoint] [%d] [%d] call_interceptor_before:redis::info return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::info end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::info 
+case: redis() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::info
+Redis::info before:  
+[pinpoint] [%d] [%d] call_interceptor_before:redis::info return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::info end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::info 
+case: redis() 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::info
+Redis::info before:  
+[pinpoint] [%d] [%d] call_interceptor_before:redis::info return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::info end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::info 
+case: strings 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::get
+Redis::get before: a 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::get return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::get end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::get 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::set
+Redis::set before: a : b 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::set return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::set end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::set 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::setnx
+Redis::setNx before: a : 10 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::setnx return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::setNx end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::setnx 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::append
+Redis::append before: ar : aa 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::append return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::append end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::append 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::setrange
+Redis::setRange before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::setrange return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::setRange end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::setrange 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::get
+Redis::get before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::get return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::get end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::get 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::getrange
+Redis::getRange before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::getrange return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::getRange end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::getrange 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::strlen
+Redis::strlen before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::strlen return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::strlen end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::strlen 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::getbit
+Redis::getBit before: ar : 1 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::getbit return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::getBit end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::getbit 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::setbit
+Redis::setBit before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::setbit return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::setBit end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::setbit 
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::get
+Redis::get before: ar 
+[pinpoint] [%d] [%d] call_interceptor_before:redis::get return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::get end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::get 
+string(2) "bb"
+[pinpoint] [%d] [%d]pinpoint_interceptor_handler_entry: handle func/method:redis::mset
+Redis::mSet before:  
+[pinpoint] [%d] [%d] call_interceptor_before:redis::mset return type(1) zval
+[pinpoint] [%d] [%d]replace_ex_caller_parameters return value must be `an array`
+Redis::mSet end 
+[pinpoint] [%d] [%d]call_interceptor_end: redis::mset 
+int(3)
+[pinpoint] [%d] [%d]start free interceptor: redis::info
+[pinpoint] [%d] [%d]start free interceptor: redis::get
+[pinpoint] [%d] [%d]start free interceptor: redis::set
+[pinpoint] [%d] [%d]start free interceptor: redis::setnx
+[pinpoint] [%d] [%d]start free interceptor: redis::append
+[pinpoint] [%d] [%d]start free interceptor: redis::getrange
+[pinpoint] [%d] [%d]start free interceptor: redis::setrange
+[pinpoint] [%d] [%d]start free interceptor: redis::strlen
+[pinpoint] [%d] [%d]start free interceptor: redis::getbit
+[pinpoint] [%d] [%d]start free interceptor: redis::setbit
+[pinpoint] [%d] [%d]start free interceptor: redis::mset
+[pinpoint] [%d] [%d]start free interceptor: redis::msetnx
\ No newline at end of file
diff --git a/tests_win32/stack_fetal_error.phpt b/tests_win32/stack_fetal_error.phpt
new file mode 100644
index 00000000..16ed5924
--- /dev/null
+++ b/tests_win32/stack_fetal_error.phpt
@@ -0,0 +1,62 @@
+--TEST--
+pinpoint_php internal test case [pinpoint_test_main]
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+
+class Foo{
+    public  function __construct()
+    {
+        _pinpoint_start_trace();
+        _pinpoint_add_clue("name","Foo");
+    }
+
+    public function __destruct()
+    {
+        _pinpoint_end_trace();
+    }
+
+    public function ouput($a,$b)
+    {
+        _pinpoint_add_clues("1","$a,$b");
+        _pinpoint_add_clues("2","234");
+    }
+}
+
+function Test(){
+    throw new \Exception("I am testting");
+}
+
+_pinpoint_start_trace();
+
+try{
+    $f = new Foo();
+    Test();
+}catch(\Exception $e){
+    throw $e;
+}
+
+_pinpoint_start_trace();
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+[pinpoint] [%d] [%d] [127] add clue key:name value:Foo
+[pinpoint] [%d] [%d]apm_error_cb called
+
+Fatal error: Uncaught Exception: I am testting in %s:23
+Stack trace:
+#0 %s(30): Test()
+#1 {main}
+  thrown in %s on line 23
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"ERR":{"file":"%s","line":23,"msg":"Uncaught Exception: I am testting in %s:23\nStack trace:\n#0 %s(30): Test()\n#1 {main}\n  thrown"},"calls":[{":E":%d,":S":%d,"name":"Foo"}]})
+[pinpoint] [%d] [%d]agent try to connect:(localhost:10000)
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
\ No newline at end of file
diff --git a/tests_win32/trace_api_context_tcp.phpt b/tests_win32/trace_api_context_tcp.phpt
new file mode 100644
index 00000000..d6323c3e
--- /dev/null
+++ b/tests_win32/trace_api_context_tcp.phpt
@@ -0,0 +1,69 @@
+--TEST--
+Check  call statck
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:127.0.0.1:9999
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+
+
+_pinpoint_start_trace();
+
+_pinpoint_set_context('a','a');
+var_dump(_pinpoint_get_context('a'));
+_pinpoint_set_context('b','b');
+var_dump(_pinpoint_get_context('b'));
+
+_pinpoint_set_context('c','c');
+var_dump(_pinpoint_get_context('c'));
+
+var_dump(_pinpoint_get_context('not exist'));
+
+_pinpoint_end_trace();
+
+$id = _pinpoint_start_trace(0);
+$id = _pinpoint_start_trace($id);
+_pinpoint_set_context('a','a',$id);
+_pinpoint_set_context('b','b',$id);
+_pinpoint_set_context('c','c',$id);
+
+var_dump(_pinpoint_get_context('c',$id));
+var_dump(_pinpoint_get_context('b',$id));
+var_dump(_pinpoint_get_context('a',$id));
+var_dump(_pinpoint_get_context('not exist',$id));
+
+$id = _pinpoint_end_trace($id);
+_pinpoint_end_trace($id);
+pinpoint_status();
+?>
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+string(1) "a"
+string(1) "b"
+string(1) "c"
+[pinpoint] [%d] [%d] pinpoint_get_context_key [128] failed with invalid map<K, T> key, parameters:not exist
+bool(false)
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d})
+[pinpoint] [%d] [%d]agent try to connect:(127.0.0.1:9999)
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+string(1) "c"
+string(1) "b"
+string(1) "a"
+[pinpoint] [%d] [%d] pinpoint_get_context_key [127] failed with invalid map<K, T> key, parameters:not exist
+bool(false)
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"calls":[{":E":%d,":S":%d}]})
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+{
+	"common_library_version" : "%s",
+	"pool_free_node" : 128,
+	"pool_total_node" : 128
+}
\ No newline at end of file
diff --git a/tests_win32/trace_api_test.phpt b/tests_win32/trace_api_test.phpt
new file mode 100644
index 00000000..362d035a
--- /dev/null
+++ b/tests_win32/trace_api_test.phpt
@@ -0,0 +1,134 @@
+--TEST--
+Check  call statck
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+
+class Foo{
+    public  function __construct()
+    {
+        echo _pinpoint_start_trace()."\n";
+        _pinpoint_add_clue("name","Foo");
+    }
+
+    public function __destruct()
+    {
+        echo _pinpoint_end_trace()."\n";
+    }
+
+    public function ouput($a,$b)
+    {
+        _pinpoint_add_clues("1","$a,$b");
+        _pinpoint_add_clues("2","234");
+    }
+}
+
+function ouput_234($a,$b)
+{
+     $foo = new Foo();
+     $foo->ouput("234",3432);
+     usleep(2000);
+}
+
+
+echo _pinpoint_start_trace()."\n";
+
+_pinpoint_add_clue("name","ouput_234");
+for($x = 0;$x <10;$x++){
+    ouput_234(1,3);
+}
+_pinpoint_add_clue("args",'a,$b');
+_pinpoint_add_clue("ret",'a,$b');
+
+echo _pinpoint_end_trace()."\n";
+
+
+?>
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+128
+[pinpoint] [%d] [%d] [128] add clue key:name value:ouput_234
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+127
+[pinpoint] [%d] [%d] [127] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [127] add clues:1:234,3432
+[pinpoint] [%d] [%d] [127] add clues:2:234
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [126]
+126
+[pinpoint] [%d] [%d] [126] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [126] add clues:1:234,3432
+[pinpoint] [%d] [%d] [126] add clues:2:234
+[pinpoint] [%d] [%d] [126] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [125]
+125
+[pinpoint] [%d] [%d] [125] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [125] add clues:1:234,3432
+[pinpoint] [%d] [%d] [125] add clues:2:234
+[pinpoint] [%d] [%d] [125] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [124]
+124
+[pinpoint] [%d] [%d] [124] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [124] add clues:1:234,3432
+[pinpoint] [%d] [%d] [124] add clues:2:234
+[pinpoint] [%d] [%d] [124] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [123]
+123
+[pinpoint] [%d] [%d] [123] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [123] add clues:1:234,3432
+[pinpoint] [%d] [%d] [123] add clues:2:234
+[pinpoint] [%d] [%d] [123] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [122]
+122
+[pinpoint] [%d] [%d] [122] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [122] add clues:1:234,3432
+[pinpoint] [%d] [%d] [122] add clues:2:234
+[pinpoint] [%d] [%d] [122] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [121]
+121
+[pinpoint] [%d] [%d] [121] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [121] add clues:1:234,3432
+[pinpoint] [%d] [%d] [121] add clues:2:234
+[pinpoint] [%d] [%d] [121] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [120]
+120
+[pinpoint] [%d] [%d] [120] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [120] add clues:1:234,3432
+[pinpoint] [%d] [%d] [120] add clues:2:234
+[pinpoint] [%d] [%d] [120] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [119]
+119
+[pinpoint] [%d] [%d] [119] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [119] add clues:1:234,3432
+[pinpoint] [%d] [%d] [119] add clues:2:234
+[pinpoint] [%d] [%d] [119] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [118]
+118
+[pinpoint] [%d] [%d] [118] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [118] add clues:1:234,3432
+[pinpoint] [%d] [%d] [118] add clues:2:234
+[pinpoint] [%d] [%d] [118] pinpoint_end_trace Done!
+128
+[pinpoint] [%d] [%d] [128] add clue key:args value:a,$b
+[pinpoint] [%d] [%d] [128] add clue key:ret value:a,$b
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"args":"a,$b","calls":[{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"},{":E":%d,":S":%d,"clues":["1:234,3432","2:234"],"name":"Foo"}],"name":"ouput_234","ret":"a,$b"})
+[pinpoint] [%d] [%d]agent try to connect:(localhost:10000)
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+0
\ No newline at end of file
diff --git a/tests_win32/trace_api_with_id.phpt b/tests_win32/trace_api_with_id.phpt
new file mode 100644
index 00000000..627a5626
--- /dev/null
+++ b/tests_win32/trace_api_with_id.phpt
@@ -0,0 +1,65 @@
+--TEST--
+Test pinpoint_unique_id
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+$id = 0;
+
+function exception_handler($exception) {
+    global $id;
+
+    $lastId = $id;
+    _pinpoint_add_clue("EXP",$exception->getMessage(),$id);
+
+    do
+    {
+        $lastId = _pinpoint_end_trace($lastId);
+    }while($lastId != 0);
+    echo "Uncaught exception: " , $exception->getMessage(), "\n";
+}
+
+set_exception_handler('exception_handler');
+
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clue("name","Foo",$id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clues("name","Foo1",$id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clue("name","Foo2",$id);
+$id = _pinpoint_end_trace($id);
+$id = _pinpoint_start_trace($id);
+_pinpoint_add_clues("name","Foo3",$id);
+_pinpoint_add_clue("name","Foo4",$id);
+$id = _pinpoint_end_trace($id);
+_pinpoint_add_clues("name","Foo5",$id);
+throw  new Exception("too heavy, throw it");
+$id = _pinpoint_end_trace($id);
+_pinpoint_add_clue("name","Foo",$id);
+
+$id = _pinpoint_end_trace($id);
+
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] add clue key:name value:Foo
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+[pinpoint] [%d] [%d] [127] add clues:name:Foo1
+[pinpoint] [%d] [%d] [127] pinpoint_start child  [126]
+[pinpoint] [%d] [%d] [126] add clue key:name value:Foo2
+[pinpoint] [%d] [%d] [126] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d] [127] pinpoint_start child  [125]
+[pinpoint] [%d] [%d] [125] add clues:name:Foo3
+[pinpoint] [%d] [%d] [125] add clue key:name value:Foo4
+[pinpoint] [%d] [%d] [125] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d] [127] add clues:name:Foo5
+[pinpoint] [%d] [%d] [127] add clue key:EXP value:too heavy, throw it
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]this span:({":E":%d,":FT":1500,":S":%d,"calls":[{":E":%d,":S":%d,"EXP":"too heavy, throw it","calls":[{":E":%d,":S":%d,"name":"Foo2"},{":E":%d,":S":%d,"clues":["name:Foo3"],"name":"Foo4"}],"clues":["name:Foo1","name:Foo5"]}],"name":"Foo"})
+[pinpoint] [%d] [%d]agent try to connect:(localhost:10000)
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
+Uncaught exception: too heavy, throw it
\ No newline at end of file
diff --git a/tests_win32/trace_limit_test-i448.phpt b/tests_win32/trace_limit_test-i448.phpt
new file mode 100644
index 00000000..fc062b31
--- /dev/null
+++ b/tests_win32/trace_limit_test-i448.phpt
@@ -0,0 +1,48 @@
+--TEST--
+Check tracelimit
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=200
+pinpoint_php.UnitTest=true
+pinpoint_php.TraceLimit=0
+;pinpoint_php._limit for internal use. does not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+
+$id = _pinpoint_start_trace(0);
+$id = _pinpoint_start_trace($id);
+_pinpoint_set_context('a','a',$id);
+_pinpoint_set_context('b','b',$id);
+_pinpoint_set_context('c','c',$id);
+
+var_dump(_pinpoint_get_context('c',$id));
+var_dump(_pinpoint_get_context('b',$id));
+var_dump(_pinpoint_get_context('a',$id));
+var_dump(_pinpoint_get_context('not exist',$id));
+
+$id = _pinpoint_end_trace($id);
+
+if(_pinpoint_trace_limit())
+{
+   _pinpoint_drop_trace($id);
+}
+
+_pinpoint_end_trace($id);
+
+--EXPECTF--
+[pinpoint] [%d] [%d] [0] pinpoint_start child  [128]
+[pinpoint] [%d] [%d] [128] pinpoint_start child  [127]
+string(1) "c"
+string(1) "b"
+string(1) "a"
+[pinpoint] [%d] [%d] pinpoint_get_context_key [127] failed with invalid map<K, T> key, parameters:not exist
+bool(false)
+[pinpoint] [%d] [%d] [127] pinpoint_end_trace Done!
+[pinpoint] [%d] [%d]This span dropped. max_trace_limit:0 current_tick:0 onLine:0
+[pinpoint] [%d] [%d]change current [128] status, before:2,now:4
+[pinpoint] [%d] [%d]current [128] span dropped,due to TRACE_BLOCK
+[pinpoint] [%d] [%d] [128] pinpoint_end_trace Done!
\ No newline at end of file
diff --git a/tests_win32/trace_limit_test.phpt b/tests_win32/trace_limit_test.phpt
new file mode 100644
index 00000000..40162c5c
--- /dev/null
+++ b/tests_win32/trace_limit_test.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Check tracelimit
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=200
+pinpoint_php.UnitTest=true
+pinpoint_php.TraceLimit=2
+;pinpoint_php._limit for internal use. User do not use it
+pinpoint_php._limit=yes
+pinpoint_php.DebugReport=true
+--FILE--
+<?php 
+if(_pinpoint_trace_limit() || _pinpoint_trace_limit() ||_pinpoint_trace_limit() || _pinpoint_trace_limit())
+{
+    echo "pass";
+}else{
+    echo "_pinpoint_trace_limit failed";
+}
+--EXPECTF--
+[pinpoint] [%d] [%d]This span dropped. max_trace_limit:2 current_tick:2 onLine:0
+pass
\ No newline at end of file
diff --git a/tests_win32/unique_api_test.phpt b/tests_win32/unique_api_test.phpt
new file mode 100644
index 00000000..b2ce343d
--- /dev/null
+++ b/tests_win32/unique_api_test.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Test pinpoint_unique_id
+--SKIPIF--
+<?php if (!extension_loaded("pinpoint_php")) print "skip"; ?>
+--INI--
+pinpoint_php.CollectorHost=tcp:localhost:10000
+pinpoint_php.SendSpanTimeOutMs=0
+pinpoint_php.UnitTest=true
+pinpoint_php.DebugReport=true
+--FILE--
+<?php
+ 
+$v1= _pinpoint_unique_id();
+$v2= _pinpoint_unique_id();
+$v3= _pinpoint_unique_id();
+var_dump( $v2*2 === $v1+$v3 );
+
+--EXPECTF--
+bool(true)
\ No newline at end of file