diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4cd4bd7..aed4718 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -23,7 +23,7 @@ jobs:
         run: composer validate --strict
 
       - name: Cache Composer packages
-        uses: actions/cache@v2
+        uses: actions/cache@v3
         with:
           path: vendor
           key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}
diff --git a/src/EvaluationCore/EvaluationEngine.php b/src/EvaluationCore/EvaluationEngine.php
index 8590b8a..140b0eb 100644
--- a/src/EvaluationCore/EvaluationEngine.php
+++ b/src/EvaluationCore/EvaluationEngine.php
@@ -1,11 +1,22 @@
 <?php
 
 namespace AmplitudeExperiment\EvaluationCore;
+
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationFlag;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationVariant;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationSegment;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationCondition;
 use Exception;
 
 require_once __DIR__ . '/Util.php';
+
 class EvaluationEngine
 {
+    /**
+     * @param array<string, mixed> $context
+     * @param EvaluationFlag[] $flags
+     * @return array<string, EvaluationVariant>
+     */
     public function evaluate(array $context, array $flags): array
     {
         $results = [];
@@ -17,46 +28,62 @@ public function evaluate(array $context, array $flags): array
         foreach ($flags as $flag) {
             $variant = $this->evaluateFlag($target, $flag);
             if ($variant !== null) {
-                $results[$flag['key']] = $variant;
+                $results[$flag->key] = $variant;
             }
         }
 
         return $results;
     }
 
-    private function evaluateFlag(array $target, array $flag): ?array
+    /**
+     * @param array<string, mixed> $target
+     * @param EvaluationFlag $flag
+     * @return EvaluationVariant|null
+     */
+    private function evaluateFlag(array $target, EvaluationFlag $flag): ?EvaluationVariant
     {
         $result = null;
 
-        foreach ($flag['segments'] as $segment) {
+        foreach ($flag->segments as $segment) {
             $result = $this->evaluateSegment($target, $flag, $segment);
             if ($result !== null) {
                 $metadata = array_merge(
-                    $flag['metadata'] ?? [],
-                    $segment['metadata'] ?? [],
-                    $result['metadata'] ?? []
+                    $flag->metadata ?? [],
+                    $segment->metadata ?? [],
+                    $result->metadata ?? []
+                );
+
+                return new EvaluationVariant(
+                    $result->key,
+                    $result->value,
+                    $result->payload,
+                    $metadata
                 );
-                $result = array_merge($result, ['metadata' => $metadata]);
-                break;
             }
         }
         return $result;
     }
 
 
-    private function evaluateSegment(array $target, array $flag, array $segment): ?array
+    /**
+     * @param array<string, mixed> $target
+     * @param EvaluationFlag $flag
+     * @param EvaluationSegment $segment
+     * @return EvaluationVariant|null
+     */
+    private function evaluateSegment(array $target, EvaluationFlag $flag, EvaluationSegment $segment): ?EvaluationVariant
     {
-        if (!isset($segment['conditions'])) {
+        if ($segment->conditions === null) {
             $variantKey = $this->bucket($target, $segment);
 
-            if ($variantKey !== null) {
-                return $flag['variants'][$variantKey];
+            if ($variantKey !== null && isset($flag->variants[$variantKey])) {
+                return $flag->variants[$variantKey];
             } else {
                 return null;
             }
         }
 
-        foreach ($segment['conditions'] as $conditions) {
+        foreach ($segment->conditions as $conditions) {
             $match = true;
 
             foreach ($conditions as $condition) {
@@ -70,8 +97,8 @@ private function evaluateSegment(array $target, array $flag, array $segment): ?a
             if ($match) {
                 $variantKey = $this->bucket($target, $segment);
 
-                if ($variantKey !== null) {
-                    return $flag['variants'][$variantKey];
+                if ($variantKey !== null && isset($flag->variants[$variantKey])) {
+                    return $flag->variants[$variantKey];
                 } else {
                     return null;
                 }
@@ -81,28 +108,35 @@ private function evaluateSegment(array $target, array $flag, array $segment): ?a
         return null;
     }
 
-    private function matchCondition(array $target, array $condition): bool
+    /**
+     * @param array<string, mixed> $target
+     * @param EvaluationCondition $condition
+     * @return bool
+     */
+    private function matchCondition(array $target, EvaluationCondition $condition): bool
     {
-        $propValue = select($target, $condition['selector']);
+        $propValue = select($target, $condition->selector);
 
-        if (!$propValue && $propValue !== '0') {
-            return $this->matchNull($condition['op'], $condition['values']);
-        } elseif ($this->isSetOperator($condition['op'])) {
+        if ($propValue === null) {
+            return $this->matchNull($condition->op, $condition->values);
+        } elseif (is_bool($propValue)) {
+            return $this->matchBoolean($propValue, $condition->op, $condition->values);
+        } elseif ($this->isSetOperator($condition->op)) {
             $propValueStringList = $this->coerceStringArray($propValue);
 
             if ($propValueStringList === null) {
                 return false;
             }
 
-            return $this->matchSet($propValueStringList, $condition['op'], $condition['values']);
+            return $this->matchSet($propValueStringList, $condition->op, $condition->values);
         } else {
             $propValueString = $this->coerceString($propValue);
 
             if ($propValueString !== null) {
                 return $this->matchString(
                     $propValueString,
-                    $condition['op'],
-                    $condition['values']
+                    $condition->op,
+                    $condition->values
                 );
             } else {
                 return false;
@@ -110,47 +144,61 @@ private function matchCondition(array $target, array $condition): bool
         }
     }
 
+    /**
+     * @param string $key
+     * @return int
+     */
     private function getHash(string $key): int
     {
         return Murmur3::hash3_int($key);
     }
 
-    private function bucket(array $target, array $segment): ?string
+    /**
+     * @param array<string, mixed> $target
+     * @param EvaluationSegment $segment
+     * @return string|null
+     */
+    private function bucket(array $target, EvaluationSegment $segment): ?string
     {
-        if (!isset($segment['bucket'])) {
-            return $segment['variant'] ?? null;
+        if ($segment->bucket === null) {
+            return $segment->variant ?? null;
         }
 
-        $bucketingValue = $this->coerceString(select($target, $segment['bucket']['selector']));
+        $bucketingValue = $this->coerceString(select($target, $segment->bucket->selector));
 
         if ($bucketingValue === null || strlen($bucketingValue) === 0) {
-            return $segment['variant'] ?? null;
+            return $segment->variant ?? null;
         }
 
-        $keyToHash = "{$segment['bucket']['salt']}/$bucketingValue";
+        $keyToHash = "{$segment->bucket->salt}/$bucketingValue";
         $hash = $this->getHash($keyToHash);
         $allocationValue = $hash % 100;
         $distributionValue = floor($hash / 100);
 
-        foreach ($segment['bucket']['allocations'] as $allocation) {
-            $allocationStart = $allocation['range'][0];
-            $allocationEnd = $allocation['range'][1];
+        foreach ($segment->bucket->allocations as $allocation) {
+            $allocationStart = $allocation->range[0];
+            $allocationEnd = $allocation->range[1];
 
             if ($allocationValue >= $allocationStart && $allocationValue < $allocationEnd) {
-                foreach ($allocation['distributions'] as $distribution) {
-                    $distributionStart = $distribution['range'][0];
-                    $distributionEnd = $distribution['range'][1];
+                foreach ($allocation->distributions as $distribution) {
+                    $distributionStart = $distribution->range[0];
+                    $distributionEnd = $distribution->range[1];
 
                     if ($distributionValue >= $distributionStart && $distributionValue < $distributionEnd) {
-                        return $distribution['variant'];
+                        return $distribution->variant;
                     }
                 }
             }
         }
 
-        return $segment['variant'] ?? null;
+        return $segment->variant ?? null;
     }
 
+    /**
+     * @param string $op
+     * @param array<string> $filterValues
+     * @return bool
+     */
     private function matchNull(string $op, array $filterValues): bool
     {
         $containsNone = $this->containsNone($filterValues);
@@ -180,6 +228,12 @@ private function matchNull(string $op, array $filterValues): bool
         }
     }
 
+    /**
+     * @param array<string> $propValues
+     * @param string $op
+     * @param array<string> $filterValues
+     * @return bool
+     */
     private function matchSet(array $propValues, string $op, array $filterValues): bool
     {
         switch ($op) {
@@ -200,6 +254,12 @@ private function matchSet(array $propValues, string $op, array $filterValues): b
         }
     }
 
+    /**
+     * @param string $propValue
+     * @param string $op
+     * @param array<string> $filterValues
+     * @return bool
+     */
     private function matchString(string $propValue, string $op, array $filterValues): bool
     {
         switch ($op) {
@@ -219,10 +279,8 @@ private function matchString(string $propValue, string $op, array $filterValues)
                     $propValue,
                     $op,
                     $filterValues,
-                    function ($value) {
-                        return $this->parseNumber($value);
-                    },
-                    array($this, 'comparator')
+                    fn(string $value): ?int => $this->parseNumber($value),
+                    fn($a, string $op, $b): bool => $this->comparator($a, $op, $b)
                 );
             case EvaluationOperator::VERSION_LESS_THAN:
             case EvaluationOperator::VERSION_LESS_THAN_EQUALS:
@@ -232,10 +290,8 @@ function ($value) {
                     $propValue,
                     $op,
                     $filterValues,
-                    function ($value) {
-                        return SemanticVersion::parse($value);
-                    },
-                    array($this, 'versionComparator')
+                    fn(string $value): ?SemanticVersion => SemanticVersion::parse($value),
+                    fn(SemanticVersion $a, string $op, SemanticVersion $b): bool => $this->versionComparator($a, $op, $b)
                 );
             case EvaluationOperator::REGEX_MATCH:
                 return $this->matchesRegex($propValue, $filterValues);
@@ -246,21 +302,30 @@ function ($value) {
         }
     }
 
+    /**
+     * @param string $propValue
+     * @param array<string> $filterValues
+     * @return bool
+     */
     private function matchesIs(string $propValue, array $filterValues): bool
     {
-        if ($this->containsBooleans($filterValues)) {
-            $lower = strtolower($propValue);
-            if ($lower === 'true' || $lower === 'false') {
-                foreach ($filterValues as $value) {
-                    if (strtolower($value) === $lower) {
-                        return true;
-                    }
-                }
-            }
+        $lowerFilterValues = array_map('strtolower', $filterValues);
+        $lowerPropValue = strtolower($propValue);
+        if (in_array('true', $lowerFilterValues) && in_array($lowerPropValue, ['true', '1'])) {
+            return true;
+        }
+
+        if (in_array('false', $lowerFilterValues) && in_array($lowerPropValue, ['false', '0'])) {
+            return true;
         }
         return in_array($propValue, $filterValues);
     }
 
+    /**
+     * @param string $propValue
+     * @param array<string> $filterValues
+     * @return bool
+     */
     private function matchesContains(string $propValue, array $filterValues): bool
     {
         foreach ($filterValues as $filterValue) {
@@ -350,17 +415,6 @@ private function containsNone(array $filterValues): bool
         return in_array('(none)', $filterValues);
     }
 
-    private function containsBooleans(array $filterValues): bool
-    {
-        foreach ($filterValues as $filterValue) {
-            $lowercaseFilterValue = strtolower($filterValue);
-            if ($lowercaseFilterValue === 'true' || $lowercaseFilterValue === 'false') {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private function parseNumber(string $value): ?int
     {
         $parsedValue = filter_var($value, FILTER_VALIDATE_INT);
@@ -387,7 +441,7 @@ private function coerceStringArray($value): ?array
         try {
             $parsedValue = json_decode($stringValue, true);
             if (is_array($parsedValue)) {
-                return array_filter(array_map([$this, 'coerceString'], $value));
+                return array_filter(array_map([$this, 'coerceString'], $parsedValue));
             } else {
                 return null;
             }
@@ -442,5 +496,38 @@ private function matchesSetContainsAny(array $propValues, array $filterValues):
         }
         return false;
     }
-}
 
+    /**
+     * @param bool $propValue
+     * @param string $op
+     * @param array<string> $filterValues
+     * @return bool
+     */
+    private function matchBoolean(bool $propValue, string $op, array $filterValues): bool
+    {
+        $propValueString = $propValue ? 'true' : 'false';
+
+        switch ($op) {
+            case EvaluationOperator::IS:
+                foreach ($filterValues as $value) {
+                    $lowercaseValue = strtolower($value);
+                    if (($propValue && $lowercaseValue === 'true') ||
+                        (!$propValue && $lowercaseValue === 'false')) {
+                        return true;
+                    }
+                }
+                return false;
+            case EvaluationOperator::IS_NOT:
+                foreach ($filterValues as $value) {
+                    $lowercaseValue = strtolower($value);
+                    if (($propValue && $lowercaseValue === 'true') ||
+                        (!$propValue && $lowercaseValue === 'false')) {
+                        return false;
+                    }
+                }
+                return true;
+            default:
+                return $this->matchString($propValueString, $op, $filterValues);
+        }
+    }
+}
diff --git a/src/EvaluationCore/EvaluationOperator.php b/src/EvaluationCore/EvaluationOperator.php
index 7f8b9dd..94796a6 100644
--- a/src/EvaluationCore/EvaluationOperator.php
+++ b/src/EvaluationCore/EvaluationOperator.php
@@ -1,27 +1,28 @@
 <?php
+declare(strict_types=1);
 
 namespace AmplitudeExperiment\EvaluationCore;
 
 class EvaluationOperator
 {
-    const IS = 'is';
-    const IS_NOT = 'is not';
-    const CONTAINS = 'contains';
-    const DOES_NOT_CONTAIN = 'does not contain';
-    const LESS_THAN = 'less';
-    const LESS_THAN_EQUALS = 'less or equal';
-    const GREATER_THAN = 'greater';
-    const GREATER_THAN_EQUALS = 'greater or equal';
-    const VERSION_LESS_THAN = 'version less';
-    const VERSION_LESS_THAN_EQUALS = 'version less or equal';
-    const VERSION_GREATER_THAN = 'version greater';
-    const VERSION_GREATER_THAN_EQUALS = 'version greater or equal';
-    const SET_IS = 'set is';
-    const SET_IS_NOT = 'set is not';
-    const SET_CONTAINS = 'set contains';
-    const SET_DOES_NOT_CONTAIN = 'set does not contain';
-    const SET_CONTAINS_ANY = 'set contains any';
-    const SET_DOES_NOT_CONTAIN_ANY = 'set does not contain any';
-    const REGEX_MATCH = 'regex match';
-    const REGEX_DOES_NOT_MATCH = 'regex does not match';
+    public const IS = 'is';
+    public const IS_NOT = 'is not';
+    public const CONTAINS = 'contains';
+    public const DOES_NOT_CONTAIN = 'does not contain';
+    public const LESS_THAN = 'less';
+    public const LESS_THAN_EQUALS = 'less or equal';
+    public const GREATER_THAN = 'greater';
+    public const GREATER_THAN_EQUALS = 'greater or equal';
+    public const VERSION_LESS_THAN = 'version less';
+    public const VERSION_LESS_THAN_EQUALS = 'version less or equal';
+    public const VERSION_GREATER_THAN = 'version greater';
+    public const VERSION_GREATER_THAN_EQUALS = 'version greater or equal';
+    public const SET_IS = 'set is';
+    public const SET_IS_NOT = 'set is not';
+    public const SET_CONTAINS = 'set contains';
+    public const SET_DOES_NOT_CONTAIN = 'set does not contain';
+    public const SET_CONTAINS_ANY = 'set contains any';
+    public const SET_DOES_NOT_CONTAIN_ANY = 'set does not contain any';
+    public const REGEX_MATCH = 'regex match';
+    public const REGEX_DOES_NOT_MATCH = 'regex does not match';
 }
diff --git a/src/EvaluationCore/Types/EvaluationAllocation.php b/src/EvaluationCore/Types/EvaluationAllocation.php
new file mode 100644
index 0000000..54731cf
--- /dev/null
+++ b/src/EvaluationCore/Types/EvaluationAllocation.php
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+
+namespace AmplitudeExperiment\EvaluationCore\Types;
+
+class EvaluationAllocation
+{
+    /** @var array<int> */
+    public array $range;
+
+    /** @var EvaluationDistribution[] */
+    public array $distributions;
+
+    /**
+     * @param array<int> $range
+     * @param EvaluationDistribution[] $distributions
+     */
+    public function __construct(
+        array $range,
+        array $distributions
+    ) {
+        $this->range = $range;
+        $this->distributions = $distributions;
+    }
+}
diff --git a/src/EvaluationCore/Types/EvaluationBucket.php b/src/EvaluationCore/Types/EvaluationBucket.php
new file mode 100644
index 0000000..2daeb6b
--- /dev/null
+++ b/src/EvaluationCore/Types/EvaluationBucket.php
@@ -0,0 +1,31 @@
+<?php
+declare(strict_types=1);
+
+namespace AmplitudeExperiment\EvaluationCore\Types;
+
+class EvaluationBucket
+{
+    /** @var array<string> */
+    public array $selector;
+
+    /** @var string */
+    public string $salt;
+
+    /** @var EvaluationAllocation[] */
+    public array $allocations;
+
+    /**
+     * @param array<string> $selector
+     * @param string $salt
+     * @param EvaluationAllocation[] $allocations
+     */
+    public function __construct(
+        array $selector,
+        string $salt,
+        array $allocations
+    ) {
+        $this->selector = $selector;
+        $this->salt = $salt;
+        $this->allocations = $allocations;
+    }
+}
diff --git a/src/EvaluationCore/Types/EvaluationCondition.php b/src/EvaluationCore/Types/EvaluationCondition.php
new file mode 100644
index 0000000..3a3e0a9
--- /dev/null
+++ b/src/EvaluationCore/Types/EvaluationCondition.php
@@ -0,0 +1,31 @@
+<?php
+declare(strict_types=1);
+
+namespace AmplitudeExperiment\EvaluationCore\Types;
+
+class EvaluationCondition
+{
+    /** @var array<string> */
+    public array $selector;
+
+    /** @var string */
+    public string $op;
+
+    /** @var array<string> */
+    public array $values;
+
+    /**
+     * @param array<string> $selector
+     * @param string $op
+     * @param array<string> $values
+     */
+    public function __construct(
+        array $selector,
+        string $op,
+        array $values
+    ) {
+        $this->selector = $selector;
+        $this->op = $op;
+        $this->values = $values;
+    }
+}
diff --git a/src/EvaluationCore/Types/EvaluationDistribution.php b/src/EvaluationCore/Types/EvaluationDistribution.php
new file mode 100644
index 0000000..c12691a
--- /dev/null
+++ b/src/EvaluationCore/Types/EvaluationDistribution.php
@@ -0,0 +1,25 @@
+<?php
+declare(strict_types=1);
+
+namespace AmplitudeExperiment\EvaluationCore\Types;
+
+class EvaluationDistribution
+{
+    /** @var string */
+    public string $variant;
+
+    /** @var array<int> */
+    public array $range;
+
+    /**
+     * @param string $variant
+     * @param array<int> $range
+     */
+    public function __construct(
+        string $variant,
+        array $range
+    ) {
+        $this->variant = $variant;
+        $this->range = $range;
+    }
+}
diff --git a/src/EvaluationCore/Types/EvaluationFlag.php b/src/EvaluationCore/Types/EvaluationFlag.php
new file mode 100644
index 0000000..41406d5
--- /dev/null
+++ b/src/EvaluationCore/Types/EvaluationFlag.php
@@ -0,0 +1,43 @@
+<?php
+declare(strict_types=1);
+
+namespace AmplitudeExperiment\EvaluationCore\Types;
+
+class EvaluationFlag
+{
+    /** @var array|null */
+    public ?array $metadata = null;
+
+    /** @var array<string, EvaluationVariant> */
+    public array $variants;
+
+    /** @var string */
+    public string $key;
+
+    /** @var EvaluationSegment[] */
+    public array $segments;
+
+    /** @var array|null */
+    public ?array $dependencies = null;
+
+    /**
+     * @param string $key
+     * @param array<string, EvaluationVariant> $variants
+     * @param EvaluationSegment[] $segments
+     * @param array<string>|null $dependencies
+     * @param array<string, mixed>|null $metadata
+     */
+    public function __construct(
+        string $key,
+        array  $variants,
+        array  $segments,
+        ?array $dependencies = null,
+        ?array $metadata = null
+    ) {
+        $this->dependencies = $dependencies;
+        $this->segments = $segments;
+        $this->key = $key;
+        $this->variants = $variants;
+        $this->metadata = $metadata;
+    }
+}
diff --git a/src/EvaluationCore/Types/EvaluationSegment.php b/src/EvaluationCore/Types/EvaluationSegment.php
new file mode 100644
index 0000000..186d0d5
--- /dev/null
+++ b/src/EvaluationCore/Types/EvaluationSegment.php
@@ -0,0 +1,37 @@
+<?php
+declare(strict_types=1);
+
+namespace AmplitudeExperiment\EvaluationCore\Types;
+
+class EvaluationSegment
+{
+    /** @var EvaluationBucket|null */
+    public ?EvaluationBucket $bucket;
+
+    /** @var array<array<EvaluationCondition>>|null */
+    public ?array $conditions;
+
+    /** @var string|null */
+    public ?string $variant;
+
+    /** @var array|null */
+    public ?array $metadata;
+
+    /**
+     * @param EvaluationBucket|null $bucket
+     * @param array<array<EvaluationCondition>>|null $conditions
+     * @param string|null $variant
+     * @param array<string, mixed>|null $metadata
+     */
+    public function __construct(
+        ?EvaluationBucket $bucket = null,
+        ?array $conditions = null,
+        ?string $variant = null,
+        ?array $metadata = null
+    ) {
+        $this->bucket = $bucket;
+        $this->conditions = $conditions;
+        $this->variant = $variant;
+        $this->metadata = $metadata;
+    }
+}
diff --git a/src/EvaluationCore/Types/EvaluationVariant.php b/src/EvaluationCore/Types/EvaluationVariant.php
new file mode 100644
index 0000000..d0f2b5b
--- /dev/null
+++ b/src/EvaluationCore/Types/EvaluationVariant.php
@@ -0,0 +1,45 @@
+<?php
+namespace AmplitudeExperiment\EvaluationCore\Types;
+
+class EvaluationVariant {
+    public ?string $key;
+    public $value;
+    public $payload;
+    public ?array $metadata;
+
+    public function __construct(?string $key = null, $value = null, $payload = null, ?array $metadata = null) {
+        $this->key = $key;
+        $this->value = $value;
+        $this->payload = $payload;
+        $this->metadata = $metadata;
+    }
+
+    /**
+     * Creates an EvaluationVariant from a JSON response body
+     *
+     * @param array $data The decoded JSON data
+     * @return EvaluationVariant
+     */
+    public static function fromJson(array $data): EvaluationVariant {
+        return new self(
+            $data['key'] ?? null,
+            $data['value'] ?? null,
+            $data['payload'] ?? null,
+            $data['metadata'] ?? null
+        );
+    }
+
+    /**
+     * Creates an array of EvaluationVariants from evaluation results
+     *
+     * @param array $results The evaluation results from response body
+     * @return array<string, EvaluationVariant>
+     */
+    public static function fromEvaluationResults(array $results): array {
+        $variants = [];
+        foreach ($results as $flagKey => $variantData) {
+            $variants[$flagKey] = self::fromJson($variantData);
+        }
+        return $variants;
+    }
+}
diff --git a/src/EvaluationCore/Util.php b/src/EvaluationCore/Util.php
index a363fc8..da46f40 100644
--- a/src/EvaluationCore/Util.php
+++ b/src/EvaluationCore/Util.php
@@ -2,6 +2,7 @@
 
 namespace AmplitudeExperiment\EvaluationCore;
 
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationFlag;
 use Exception;
 
 function select($selectable, $selector)
@@ -11,7 +12,16 @@ function select($selectable, $selector)
     }
 
     foreach ($selector as $selectorElement) {
-        if (!$selectorElement || !$selectable || !is_array($selectable)) {
+        if ($selectable instanceof Types\EvaluationVariant) {
+            $selectable = [
+                'key' => $selectable->key,
+                'value' => $selectable->value,
+                'payload' => $selectable->payload,
+                'metadata' => $selectable->metadata
+            ];
+        }
+
+        if (!is_bool($selectable) && (!$selectable || !is_array($selectable))) {
             return null;
         }
 
@@ -23,7 +33,8 @@ function select($selectable, $selector)
     }
 
     // "0" is falsy in PHP, so we need to check for it explicitly
-    if (!$selectable && $selectable !== '0') {
+    // Also handle boolean values explicitly
+    if ((!$selectable && $selectable !== '0' && $selectable !== 0 && $selectable !== false) || $selectable === null) {
         return null;
     } else {
         return $selectable;
@@ -31,19 +42,33 @@ function select($selectable, $selector)
 }
 
 /**
+ * @param array<string, EvaluationFlag> $flags
+ * @param string[]|null $flagKeys
+ * @return EvaluationFlag[]
  * @throws Exception
  */
-function topologicalSort($flags, $flagKeys = null): array
+function topologicalSort(array $flags, ?array $flagKeys = null): array
 {
-    $available = $flags;
+    $available = [];
+    // Index flags by key for lookup
+    foreach ($flags as $flag) {
+        $available[$flag->key] = $flag;
+    }
+
     $result = [];
-    $isNullOrEmpty = !$flagKeys || count($flagKeys) === 0;
-    $startingKeys = $isNullOrEmpty ? array_keys($available) : $flagKeys;
+    $startingKeys = $flagKeys ?? array_keys($available);
+
+    if (empty($startingKeys)) {
+        return array_values($flags);
+    }
 
     foreach ($startingKeys as $flagKey) {
+        if (!array_key_exists($flagKey, $available)) {
+            continue;
+        }
         $traversal = parentTraversal($flagKey, $available);
-        if ($traversal) {
-            $result = array_merge($result, $traversal);
+        if ($traversal !== null) {
+            array_push($result, ...$traversal);
         }
     }
 
@@ -51,35 +76,41 @@ function topologicalSort($flags, $flagKeys = null): array
 }
 
 /**
+ * @param string $flagKey
+ * @param array<string, EvaluationFlag> $available
+ * @param string[] $path
+ * @return EvaluationFlag[]|null
  * @throws Exception
  */
-function parentTraversal($flagKey, &$available, $path = []): ?array
+function parentTraversal(string $flagKey, array &$available, array $path = []): ?array
 {
     $flag = $available[$flagKey] ?? null;
-
     if (!$flag) {
         return null;
-    } elseif (empty($flag["dependencies"])) {
-        unset($available[$flag["key"]]);
+    }
+
+    if (!$flag->dependencies || empty($flag->dependencies)) {
+        unset($available[$flag->key]);
         return [$flag];
     }
 
-    $path[] = $flag["key"];
+    $path[] = $flag->key;
     $result = [];
 
-    foreach ($flag["dependencies"] as $parentKey) {
+    foreach ($flag->dependencies as $parentKey) {
         if (in_array($parentKey, $path)) {
             throw new Exception("Detected a cycle between flags " . implode(',', $path));
         }
-
-        $traversal = parentTraversal($parentKey, $available, $path);
-        if ($traversal) {
-            $result = array_merge($result, $traversal);
+        if (array_key_exists($parentKey, $available)) {
+            $traversal = parentTraversal($parentKey, $available, $path);
+            if ($traversal !== null) {
+                array_push($result, ...$traversal);
+            }
         }
     }
+
     $result[] = $flag;
     array_pop($path);
-    unset($available[$flag["key"]]);
+    unset($available[$flag->key]);
     return $result;
 }
-
diff --git a/src/Flag/FlagConfigService.php b/src/Flag/FlagConfigService.php
index 30b00de..05f5ddb 100644
--- a/src/Flag/FlagConfigService.php
+++ b/src/Flag/FlagConfigService.php
@@ -2,9 +2,13 @@
 
 namespace AmplitudeExperiment\Flag;
 
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationFlag;
+use Exception;
 use Psr\Http\Client\ClientExceptionInterface;
 use Psr\Log\LoggerInterface;
 
+require_once __DIR__ . '/Util.php';
+
 class FlagConfigService
 {
     private LoggerInterface $logger;
@@ -15,6 +19,11 @@ class FlagConfigService
      */
     public array $cache;
 
+    /**
+     * @var EvaluationFlag[]
+     */
+    private array $translatedFlags = [];
+
     /**
      * @param array<string, mixed> $bootstrap
      */
@@ -23,6 +32,7 @@ public function __construct(FlagConfigFetcher $fetcher, LoggerInterface $logger,
         $this->fetcher = $fetcher;
         $this->logger = $logger;
         $this->cache = $bootstrap;
+        $this->translateFlags();
     }
 
     public function refresh(): void
@@ -31,6 +41,7 @@ public function refresh(): void
         try {
             $flagConfigs = $this->fetcher->fetch();
             $this->cache = $flagConfigs;
+            $this->translateFlags();
         } catch (ClientExceptionInterface $error) {
             $this->logger->error('[Experiment] Failed to fetch flag configs: ' . $error->getMessage());
         }
@@ -43,4 +54,25 @@ public function getFlagConfigs(): array
     {
         return $this->cache;
     }
+
+    /**
+     * @return EvaluationFlag[]
+     */
+    public function getTranslatedFlags(): array
+    {
+        return $this->translatedFlags;
+    }
+
+    /**
+     * Translates raw flag configs into typed EvaluationFlag objects
+     */
+    private function translateFlags(): void
+    {
+        try {
+            $this->translatedFlags = createFlagsFromArray($this->cache);
+        } catch (Exception $e) {
+            $this->logger->error('[Experiment] Failed to translate flag configs: ' . $e->getMessage());
+            $this->translatedFlags = [];
+        }
+    }
 }
diff --git a/src/Flag/Util.php b/src/Flag/Util.php
new file mode 100644
index 0000000..5c29122
--- /dev/null
+++ b/src/Flag/Util.php
@@ -0,0 +1,124 @@
+<?php
+
+namespace AmplitudeExperiment\Flag;
+
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationFlag;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationVariant;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationSegment;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationBucket;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationCondition;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationDistribution;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationAllocation;
+
+/**
+ * Creates an array of EvaluationFlag objects from raw flag data
+ *
+ * @param array<string, mixed> $rawFlags
+ * @return EvaluationFlag[]
+ */
+function createFlagsFromArray(array $rawFlags): array
+{
+    $flags = [];
+
+    foreach ($rawFlags as $flagData) {
+        if (!isset($flagData['key'])) {
+            continue;
+        }
+
+        // Process variants
+        $variants = [];
+        if (isset($flagData['variants']) && is_array($flagData['variants'])) {
+            foreach ($flagData['variants'] as $variantKey => $variantData) {
+                if (!isset($variantData['key'])) {
+                    continue;
+                }
+                $variants[$variantKey] = new EvaluationVariant(
+                    $variantData['key'],
+                    $variantData['value'] ?? null,
+                    $variantData['payload'] ?? null,
+                    $variantData['metadata'] ?? null
+                );
+            }
+        }
+
+        // Process segments
+        $segments = [];
+        if (isset($flagData['segments']) && is_array($flagData['segments'])) {
+            foreach ($flagData['segments'] as $segmentData) {
+                // Process bucket if exists
+                $bucket = null;
+                if (isset($segmentData['bucket']) && is_array($segmentData['bucket'])) {
+                    $allocations = [];
+                    if (isset($segmentData['bucket']['allocations']) && is_array($segmentData['bucket']['allocations'])) {
+                        foreach ($segmentData['bucket']['allocations'] as $allocationData) {
+                            if (!isset($allocationData['distributions'], $allocationData['range'])) {
+                                continue;
+                            }
+
+                            $distributions = [];
+                            foreach ($allocationData['distributions'] as $distributionData) {
+                                if (!isset($distributionData['variant'], $distributionData['range'])) {
+                                    continue;
+                                }
+                                $distributions[] = new EvaluationDistribution(
+                                    $distributionData['variant'],
+                                    $distributionData['range']
+                                );
+                            }
+
+                            $allocations[] = new EvaluationAllocation(
+                                $allocationData['range'],
+                                $distributions
+                            );
+                        }
+                    }
+
+                    $bucket = new EvaluationBucket(
+                        $segmentData['bucket']['selector'] ?? [],
+                        $segmentData['bucket']['salt'] ?? '',
+                        $allocations
+                    );
+                }
+
+                // Process conditions if exists
+                $conditions = null;
+                if (isset($segmentData['conditions']) && is_array($segmentData['conditions'])) {
+                    $conditions = array_map(function ($conditionSet) {
+                        return array_map(function ($condition) {
+                            if (!isset($condition['op'], $condition['selector'], $condition['values'])) {
+                                return null;
+                            }
+                            return new EvaluationCondition(
+                                $condition['selector'],
+                                $condition['op'],
+                                $condition['values']
+                            );
+                        }, $conditionSet);
+                    }, $segmentData['conditions']);
+
+                    // Remove null values from conditions
+                    $conditions = array_map(function($conditionSet) {
+                        return array_filter($conditionSet);
+                    }, array_filter($conditions));
+                }
+
+                $segments[] = new EvaluationSegment(
+                    $bucket,
+                    $conditions,
+                    $segmentData['variant'] ?? null,
+                    $segmentData['metadata'] ?? null
+                );
+            }
+        }
+
+        $flags[] = new EvaluationFlag(
+            $flagData['key'],
+            $variants,
+            $segments,
+            $flagData['dependencies'] ?? null,
+            $flagData['metadata'] ?? null
+        );
+    }
+
+    return $flags;
+}
diff --git a/src/Local/LocalEvaluationClient.php b/src/Local/LocalEvaluationClient.php
index b40bbe7..01e745e 100644
--- a/src/Local/LocalEvaluationClient.php
+++ b/src/Local/LocalEvaluationClient.php
@@ -5,6 +5,7 @@
 use AmplitudeExperiment\Assignment\AssignmentConfig;
 use AmplitudeExperiment\Assignment\AssignmentService;
 use AmplitudeExperiment\EvaluationCore\EvaluationEngine;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationFlag;
 use AmplitudeExperiment\Flag\FlagConfigFetcher;
 use AmplitudeExperiment\Flag\FlagConfigService;
 use AmplitudeExperiment\Http\GuzzleHttpClient;
@@ -58,22 +59,38 @@ public function refreshFlagConfigs(): void
      * @param User $user The user to evaluate
      * @param array<string> $flagKeys The flags to evaluate with the user. If empty, all flags
      * from the flag cache are evaluated.
-     * @return array<Variant> evaluated variants
+     * @return array<string, Variant> evaluated variants
      */
     public function evaluate(User $user, array $flagKeys = []): array
     {
-        $flags = $this->flagConfigService->getFlagConfigs();
+        // Get translated flags from the flag config service
+        $flags = $this->flagConfigService->getTranslatedFlags();
+
         try {
+            // Sort flags topologically based on dependencies
             $flags = topologicalSort($flags, $flagKeys);
         } catch (\Exception $e) {
             $this->logger->error('[Experiment] Evaluate - error sorting flags: ' . $e->getMessage());
         }
-        $this->logger->debug('[Experiment] Evaluate - user: ' . json_encode($user->toArray()) . ' with flags: ' . json_encode($flags));
-        $results = array_map('AmplitudeExperiment\Variant::convertEvaluationVariantToVariant', $this->evaluation->evaluate($user->toEvaluationContext(), $flags));
+
+        $this->logger->debug('[Experiment] Evaluate - user: ' . json_encode($user->toArray()) . ' with flags: ' . json_encode(array_map(function($flag) { return $flag->key; }, $flags)));
+
+        // Evaluate the user against the flags
+        $evaluationResults = $this->evaluation->evaluate($user->toEvaluationContext(), $flags);
+
+        // Convert evaluation results to Variant objects
+        $results = [];
+        foreach ($evaluationResults as $key => $evaluationVariant) {
+            $results[$key] = Variant::convertEvaluationVariantToVariant($evaluationVariant);
+        }
+
         $this->logger->debug('[Experiment] Evaluate - variants:' . json_encode($results));
+
+        // Track assignments if assignment service is configured
         if ($this->assignmentService) {
             $this->assignmentService->track($this->assignmentService->createAssignment($user, $results));
         }
+
         return $results;
     }
 
diff --git a/src/Remote/RemoteEvaluationClient.php b/src/Remote/RemoteEvaluationClient.php
index 68ec426..addb385 100644
--- a/src/Remote/RemoteEvaluationClient.php
+++ b/src/Remote/RemoteEvaluationClient.php
@@ -2,6 +2,7 @@
 
 namespace AmplitudeExperiment\Remote;
 
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationVariant;
 use AmplitudeExperiment\Http\HttpClientInterface;
 use AmplitudeExperiment\Http\GuzzleHttpClient;
 use AmplitudeExperiment\Logger\DefaultLogger;
@@ -89,11 +90,10 @@ public function fetch(User $user, array $flagKeys = []): array
                 return [];
             }
 
-            $results = json_decode($response->getBody(), true);
-            $variants = [];
-            foreach ($results as $flagKey => $flagResult) {
-                $variants[$flagKey] = Variant::convertEvaluationVariantToVariant($flagResult);
-            }
+            $results = EvaluationVariant::fromEvaluationResults(json_decode($response->getBody(), true));
+            $variants = array_map(function ($flagResult) {
+                return Variant::convertEvaluationVariantToVariant($flagResult);
+            }, $results);
             $this->logger->debug('[Experiment] Fetched variants: ' . $response->getBody());
             return $variants;
         } catch (ClientExceptionInterface $e) {
diff --git a/src/Variant.php b/src/Variant.php
index 8486ffd..7ca1892 100644
--- a/src/Variant.php
+++ b/src/Variant.php
@@ -2,6 +2,8 @@
 
 namespace AmplitudeExperiment;
 
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationVariant;
+
 class Variant
 {
     /**
@@ -48,41 +50,39 @@ public function __construct(
     }
 
     /**
-     * @param array<mixed> $evaluationVariant
+     * Converts an EvaluationVariant to a Variant
+     *
+     * @param EvaluationVariant $evaluationVariant The evaluation variant to convert
+     * @return Variant The converted variant
      */
-    public static function convertEvaluationVariantToVariant(array $evaluationVariant): Variant
+    public static function convertEvaluationVariantToVariant(EvaluationVariant $evaluationVariant): Variant
     {
-
         $variant = new Variant();
 
-        if (empty($evaluationVariant)) {
-            return $variant;
-        }
-
         $experimentKey = null;
 
-        if (isset($evaluationVariant['metadata'])) {
-            $experimentKey = $evaluationVariant['metadata']['experimentKey'] ?? null;
+        if (isset($evaluationVariant->metadata)) {
+            $experimentKey = $evaluationVariant->metadata['experimentKey'] ?? null;
         }
 
-        if (isset($evaluationVariant['key'])) {
-            $variant->key = $evaluationVariant['key'];
+        if ($evaluationVariant->key !== null) {
+            $variant->key = $evaluationVariant->key;
         }
 
-        if (isset($evaluationVariant['value'])) {
-            $variant->value = (string)$evaluationVariant['value'];
+        if ($evaluationVariant->value !== null) {
+            $variant->value = (string)$evaluationVariant->value;
         }
 
-        if (isset($evaluationVariant['payload'])) {
-            $variant->payload = $evaluationVariant['payload'];
+        if ($evaluationVariant->payload !== null) {
+            $variant->payload = $evaluationVariant->payload;
         }
 
-        if ($experimentKey) {
+        if ($experimentKey !== null) {
             $variant->expKey = $experimentKey;
         }
 
-        if (isset($evaluationVariant['metadata'])) {
-            $variant->metadata = $evaluationVariant['metadata'];
+        if (isset($evaluationVariant->metadata)) {
+            $variant->metadata = $evaluationVariant->metadata;
         }
 
         return $variant;
diff --git a/tests/EvaluationCore/EvaluateIntegrationTest.php b/tests/EvaluationCore/EvaluateIntegrationTest.php
index 92fd5d1..acadd6c 100644
--- a/tests/EvaluationCore/EvaluateIntegrationTest.php
+++ b/tests/EvaluationCore/EvaluateIntegrationTest.php
@@ -3,15 +3,24 @@
 namespace AmplitudeExperiment\Test\EvaluationCore;
 
 use AmplitudeExperiment\EvaluationCore\EvaluationEngine;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationFlag;
+use AmplitudeExperiment\Variant;
 use Exception;
 use GuzzleHttp\Client;
 use GuzzleHttp\Exception\GuzzleException;
 use PHPUnit\Framework\TestCase;
 
+require_once __DIR__ . '/../../src/Flag/Util.php';
+use function AmplitudeExperiment\Flag\createFlagsFromArray;
+
 class EvaluateIntegrationTest extends TestCase
 {
     private EvaluationEngine $engine;
-    private $flags;
+
+    /**
+     * @var EvaluationFlag[]
+     */
+    private array $flags;
 
     /**
      * @throws GuzzleException
@@ -19,106 +28,133 @@ class EvaluateIntegrationTest extends TestCase
     protected function setUp(): void
     {
         $this->engine = new EvaluationEngine();
-        $this->flags = $this->getFlags('server-NgJxxvg8OGwwBsWVXqyxQbdiflbhvugy');
+        $rawFlags = $this->getFlags('server-NgJxxvg8OGwwBsWVXqyxQbdiflbhvugy');
+        $this->flags = createFlagsFromArray($rawFlags);
     }
 
     public function testOff()
     {
         $user = $this->userContext('user_id', 'device_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-off'];
-        $this->assertEquals('off', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-off'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('off', $variant->key);
     }
 
     public function testOn()
     {
         $user = $this->userContext('user_id', 'device_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-on'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-on'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testIndividualInclusionsMatchUserId()
     {
         $user = $this->userContext('user_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-individual-inclusions'];
-        $this->assertEquals('on', $result['key']);
-        $this->assertEquals('individual-inclusions', $result['metadata']['segmentName']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-individual-inclusions'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
+        $this->assertEquals('individual-inclusions', $variant->metadata['segmentName']);
     }
 
     public function testIndividualInclusionsMatchDeviceId()
     {
         $user = $this->userContext(null, 'device_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-individual-inclusions'];
-        $this->assertEquals('on', $result['key']);
-        $this->assertEquals('individual-inclusions', $result['metadata']['segmentName']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-individual-inclusions'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
+        $this->assertEquals('individual-inclusions', $variant->metadata['segmentName']);
     }
 
     public function testIndividualInclusionsNoMatchUserId()
     {
         $user = $this->userContext('not_user_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-individual-inclusions'];
-        $this->assertEquals('off', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-individual-inclusions'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('off', $variant->key);
     }
 
     public function testIndividualInclusionsNoMatchDeviceId()
     {
         $user = $this->userContext(null, 'not_device_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-individual-inclusions'];
-        $this->assertEquals('off', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-individual-inclusions'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('off', $variant->key);
     }
 
     public function testFlagDependenciesOn()
     {
         $user = $this->userContext('user_id', 'device_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-flag-dependencies-on'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-flag-dependencies-on'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+         $this->assertEquals('on', $variant->key);
     }
 
     public function testFlagDependenciesOff()
     {
         $user = $this->userContext('user_id', 'device_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-flag-dependencies-off'];
-        $this->assertEquals('off', $result['key']);
-        $this->assertEquals('flag-dependencies', $result['metadata']['segmentName']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-flag-dependencies-off'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('off', $variant->key);
+        $this->assertEquals('flag-dependencies', $variant->metadata['segmentName']);
     }
 
     public function testStickyBucketingOn()
     {
         $user = $this->userContext('user_id', 'device_id', null, ['[Experiment] test-sticky-bucketing' => 'on']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-sticky-bucketing'];
-        $this->assertEquals('on', $result['key']);
-        $this->assertEquals('sticky-bucketing', $result['metadata']['segmentName']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-sticky-bucketing'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
+        $this->assertEquals('sticky-bucketing', $variant->metadata['segmentName']);
     }
 
     public function testStickyBucketingOff()
     {
         $user = $this->userContext('user_id', 'device_id', null, ['[Experiment] test-sticky-bucketing' => 'off']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-sticky-bucketing'];
-        $this->assertEquals('off', $result['key']);
-        $this->assertEquals('All Other Users', $result['metadata']['segmentName']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-sticky-bucketing'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('off', $variant->key);
+        $this->assertEquals('All Other Users', $variant->metadata['segmentName']);
     }
 
     public function testStickyBucketingNonVariant()
     {
         $user = $this->userContext('user_id', 'device_id', null, ['[Experiment] test-sticky-bucketing' => 'not-a-variant']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-sticky-bucketing'];
-        $this->assertEquals('off', $result['key']);
-        $this->assertEquals('All Other Users', $result['metadata']['segmentName']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-sticky-bucketing'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('off', $variant->key);
+        $this->assertEquals('All Other Users', $variant->metadata['segmentName']);
     }
 
     public function testExperiment()
     {
         $user = $this->userContext('user_id', 'device_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-experiment'];
-        $this->assertEquals('on', $result['key']);
-        $this->assertEquals('exp-1', $result['metadata']['experimentKey']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-experiment'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
+        $this->assertEquals('exp-1', $variant->metadata['experimentKey']);
     }
 
     public function testFlag()
     {
         $user = $this->userContext('user_id', 'device_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-flag'];
-        $this->assertEquals('on', $result['key']);
-        $this->assertArrayNotHasKey('experimentKey', $result['metadata']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-flag'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
+        $this->assertArrayNotHasKey('experimentKey', $variant->metadata);
     }
 
     public function testMultipleConditionsAndValuesAllMatch()
@@ -128,8 +164,10 @@ public function testMultipleConditionsAndValuesAllMatch()
             'key-2' => 'value-2',
             'key-3' => 'value-3',
         ]);
-        $result = $this->engine->evaluate($user, $this->flags)['test-multiple-conditions-and-values'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-multiple-conditions-and-values'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testMultipleConditionsAndValuesSomeMatch()
@@ -138,85 +176,109 @@ public function testMultipleConditionsAndValuesSomeMatch()
             'key-1' => 'value-1',
             'key-2' => 'value-2',
         ]);
-        $result = $this->engine->evaluate($user, $this->flags)['test-multiple-conditions-and-values'];
-        $this->assertEquals('off', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-multiple-conditions-and-values'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('off', $variant->key);
     }
 
     public function testAmplitudePropertyTargeting()
     {
         $user = $this->userContext('user_id', 'device_id', null, ['key-1' => 'value-1']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-amplitude-property-targeting'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-amplitude-property-targeting'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testCohortTargetingOn()
     {
         $user = $this->userContext(null, null, null, null, ['u0qtvwla', '12345678']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-cohort-targeting'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-cohort-targeting'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testCohortTargetingOff()
     {
         $user = $this->userContext(null, null, null, null, ['12345678', '87654321']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-cohort-targeting'];
-        $this->assertEquals('off', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-cohort-targeting'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('off', $variant->key);
     }
 
     public function testGroupNameTargeting()
     {
         $user = $this->groupContext('org name', 'amplitude');
-        $result = $this->engine->evaluate($user, $this->flags)['test-group-name-targeting'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-group-name-targeting'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testGroupPropertyTargeting()
     {
         $user = $this->groupContext('org name', 'amplitude', ['org plan' => 'enterprise2']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-group-property-targeting'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-group-property-targeting'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testAmplitudeIdBucketing()
     {
         $user = $this->userContext(null, null, '1234567890');
-        $result = $this->engine->evaluate($user, $this->flags)['test-amplitude-id-bucketing'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-amplitude-id-bucketing'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testUserIdBucketing()
     {
         $user = $this->userContext('user_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-user-id-bucketing'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-user-id-bucketing'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testDeviceIdBucketing()
     {
         $user = $this->userContext(null, 'device_id');
-        $result = $this->engine->evaluate($user, $this->flags)['test-device-id-bucketing'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-device-id-bucketing'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testCustomUserPropertyBucketing()
     {
         $user = $this->userContext(null, null, null, ['key' => 'value']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-custom-user-property-bucketing'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-custom-user-property-bucketing'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testGroupNameBucketing()
     {
         $user = $this->groupContext('org name', 'amplitude');
-        $result = $this->engine->evaluate($user, $this->flags)['test-group-name-bucketing'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-group-name-bucketing'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testGroupPropertyBucketing()
     {
         $user = $this->groupContext('org name', 'amplitude', ['org plan' => 'enterprise2']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-group-name-bucketing'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-group-name-bucketing'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testOnePercentAllocation()
@@ -224,8 +286,10 @@ public function testOnePercentAllocation()
         $on = 0;
         for ($i = 0; $i < 10000; $i++) {
             $user = $this->userContext(null, (string)($i + 1));
-            $result = $this->engine->evaluate($user, $this->flags)['test-1-percent-allocation'];
-            if ($result['key'] === 'on') {
+            $results = $this->engine->evaluate($user, $this->flags);
+            $result = $results['test-1-percent-allocation'];
+            $variant = Variant::convertEvaluationVariantToVariant($result);
+            if ($variant->key === 'on') {
                 $on++;
             }
         }
@@ -237,8 +301,10 @@ public function testFiftyPercentAllocation()
         $on = 0;
         for ($i = 0; $i < 10000; $i++) {
             $user = $this->userContext(null, (string)($i + 1));
-            $result = $this->engine->evaluate($user, $this->flags)['test-50-percent-allocation'];
-            if ($result['key'] === 'on') {
+            $results = $this->engine->evaluate($user, $this->flags);
+            $result = $results['test-50-percent-allocation'];
+            $variant = Variant::convertEvaluationVariantToVariant($result);
+            if ($variant->key === 'on') {
                 $on++;
             }
         }
@@ -250,8 +316,10 @@ public function testNinetyNinePercentAllocation()
         $on = 0;
         for ($i = 0; $i < 10000; $i++) {
             $user = $this->userContext(null, (string)($i + 1));
-            $result = $this->engine->evaluate($user, $this->flags)['test-99-percent-allocation'];
-            if ($result['key'] === 'on') {
+            $results = $this->engine->evaluate($user, $this->flags);
+            $result = $results['test-99-percent-allocation'];
+            $variant = Variant::convertEvaluationVariantToVariant($result);
+            if ($variant->key === 'on') {
                 $on++;
             }
         }
@@ -264,10 +332,12 @@ public function testOnePercentDistribution()
         $treatment = 0;
         for ($i = 0; $i < 10000; $i++) {
             $user = $this->userContext(null, (string)($i + 1));
-            $result = $this->engine->evaluate($user, $this->flags)['test-1-percent-distribution'];
-            if ($result['key'] === 'control') {
+            $results = $this->engine->evaluate($user, $this->flags);
+            $result = $results['test-1-percent-distribution'];
+            $variant = Variant::convertEvaluationVariantToVariant($result);
+            if ($variant->key === 'control') {
                 $control++;
-            } elseif ($result['key'] === 'treatment') {
+            } elseif ($variant->key === 'treatment') {
                 $treatment++;
             }
         }
@@ -281,10 +351,12 @@ public function testFiftyPercentDistribution()
         $treatment = 0;
         for ($i = 0; $i < 10000; $i++) {
             $user = $this->userContext(null, (string)($i + 1));
-            $result = $this->engine->evaluate($user, $this->flags)['test-50-percent-distribution'];
-            if ($result['key'] === 'control') {
+            $results = $this->engine->evaluate($user, $this->flags);
+            $result = $results['test-50-percent-distribution'];
+            $variant = Variant::convertEvaluationVariantToVariant($result);
+            if ($variant->key === 'control') {
                 $control++;
-            } elseif ($result['key'] === 'treatment') {
+            } elseif ($variant->key === 'treatment') {
                 $treatment++;
             }
         }
@@ -298,10 +370,12 @@ public function testNinetyNinePercentDistribution()
         $treatment = 0;
         for ($i = 0; $i < 10000; $i++) {
             $user = $this->userContext(null, (string)($i + 1));
-            $result = $this->engine->evaluate($user, $this->flags)['test-99-percent-distribution'];
-            if ($result['key'] === 'control') {
+            $results = $this->engine->evaluate($user, $this->flags);
+            $result = $results['test-99-percent-distribution'];
+            $variant = Variant::convertEvaluationVariantToVariant($result);
+            if ($variant->key === 'control') {
                 $control++;
-            } elseif ($result['key'] === 'treatment') {
+            } elseif ($variant->key === 'treatment') {
                 $treatment++;
             }
         }
@@ -317,14 +391,16 @@ public function testMultipleDistributions()
         $d = 0;
         for ($i = 0; $i < 10000; $i++) {
             $user = $this->userContext(null, (string)($i + 1));
-            $result = $this->engine->evaluate($user, $this->flags)['test-multiple-distributions'];
-            if ($result['key'] === 'a') {
+            $results = $this->engine->evaluate($user, $this->flags);
+            $result = $results['test-multiple-distributions'];
+            $variant = Variant::convertEvaluationVariantToVariant($result);
+            if ($variant->key === 'a') {
                 $a++;
-            } elseif ($result['key'] === 'b') {
+            } elseif ($variant->key === 'b') {
                 $b++;
-            } elseif ($result['key'] === 'c') {
+            } elseif ($variant->key === 'c') {
                 $c++;
-            } elseif ($result['key'] === 'd') {
+            } elseif ($variant->key === 'd') {
                 $d++;
             }
         }
@@ -337,154 +413,200 @@ public function testMultipleDistributions()
     public function testIs()
     {
         $user = $this->userContext(null, null, null, ['key' => 'value']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-is'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-is'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testIsNot()
     {
         $user = $this->userContext(null, null, null, ['key' => 'value']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-is-not'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-is-not'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testContains()
     {
         $user = $this->userContext(null, null, null, ['key' => 'value']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-contains'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-contains'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testDoesNotContain()
     {
         $user = $this->userContext(null, null, null, ['key' => 'value']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-does-not-contain'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-does-not-contain'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testLess()
     {
         $user = $this->userContext(null, null, null, ['key' => '-1']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-less'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-less'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testLessOrEqual()
     {
         $user = $this->userContext(null, null, null, ['key' => '0']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-less-or-equal'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-less-or-equal'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testGreater()
     {
         $user = $this->userContext(null, null, null, ['key' => '1']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-greater'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-greater'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testGreaterOrEqual()
     {
         $user = $this->userContext(null, null, null, ['key' => '0']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-greater-or-equal'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-greater-or-equal'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testVersionLess()
     {
         $user = $this->freeformUserContext(['version' => '1.9.0']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-version-less'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-version-less'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testVersionLessOrEqual()
     {
         $user = $this->freeformUserContext(['version' => '1.10.0']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-version-less-or-equal'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-version-less-or-equal'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testVersionGreater()
     {
         $user = $this->freeformUserContext(['version' => '1.10.0']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-version-greater'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-version-greater'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testVersionGreaterOrEqual()
     {
         $user = $this->freeformUserContext(['version' => '1.9.0']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-version-greater-or-equal'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-version-greater-or-equal'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testSetIs()
     {
         $user = $this->userContext(null, null, null, ['key' => ['1', '2', '3']]);
-        $result = $this->engine->evaluate($user, $this->flags)['test-set-is'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-set-is'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testSetIsNot()
     {
         $user = $this->userContext(null, null, null, ['key' => ['1', '2']]);
-        $result = $this->engine->evaluate($user, $this->flags)['test-set-is-not'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-set-is-not'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testSetContains()
     {
         $user = $this->userContext(null, null, null, ['key' => ['1', '2', '3', '4']]);
-        $result = $this->engine->evaluate($user, $this->flags)['test-set-contains'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-set-contains'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testSetDoesNotContain()
     {
         $user = $this->userContext(null, null, null, ['key' => ['1', '2', '4']]);
-        $result = $this->engine->evaluate($user, $this->flags)['test-set-does-not-contain'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-set-does-not-contain'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testSetContainsAny()
     {
         $user = $this->userContext(null, null, null, null, ['u0qtvwla', '12345678']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-set-contains-any'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-set-contains-any'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testSetDoesNotContainAny()
     {
         $user = $this->userContext(null, null, null, null, ['12345678', '87654321']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-set-does-not-contain-any'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-set-does-not-contain-any'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testGlobMatch()
     {
         $user = $this->userContext(null, null, null, ['key' => '/path/1/2/3/end']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-glob-match'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-glob-match'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testGlobDoesNotMatch()
     {
         $user = $this->userContext(null, null, null, ['key' => '/path/1/2/3']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-glob-does-not-match'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-glob-does-not-match'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     public function testIsWithBooleans()
     {
         $user = $this->userContext(null, null, null, ['true' => 'TRUE', 'false' => 'FALSE']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-is-with-booleans'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-is-with-booleans'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
         $user = $this->userContext(null, null, null, ['true' => 'True', 'false' => 'False']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-is-with-booleans'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-is-with-booleans'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
         $user = $this->userContext(null, null, null, ['true' => 'true', 'false' => 'false']);
-        $result = $this->engine->evaluate($user, $this->flags)['test-is-with-booleans'];
-        $this->assertEquals('on', $result['key']);
+        $results = $this->engine->evaluate($user, $this->flags);
+        $result = $results['test-is-with-booleans'];
+        $variant = Variant::convertEvaluationVariantToVariant($result);
+        $this->assertEquals('on', $variant->key);
     }
 
     private function userContext($userId = null, $deviceId = null, $amplitudeId = null, $userProperties = [], $cohortIds = []): array
diff --git a/tests/EvaluationCore/EvaluationEngineTest.php b/tests/EvaluationCore/EvaluationEngineTest.php
new file mode 100644
index 0000000..c2c5d4e
--- /dev/null
+++ b/tests/EvaluationCore/EvaluationEngineTest.php
@@ -0,0 +1,137 @@
+<?php
+
+namespace AmplitudeExperiment\Test\EvaluationCore;
+
+use AmplitudeExperiment\EvaluationCore\EvaluationEngine;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationFlag;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationSegment;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationVariant;
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationCondition;
+use PHPUnit\Framework\TestCase;
+
+class EvaluationEngineTest extends TestCase
+{
+    private EvaluationEngine $engine;
+
+    protected function setUp(): void
+    {
+        $this->engine = new EvaluationEngine();
+    }
+
+    public function testBooleanMatching()
+    {
+        $variants = [
+            'on' => new EvaluationVariant('on'),
+            'off' => new EvaluationVariant('off')
+        ];
+
+        // Create test segments for different boolean conditions
+        $trueSegment = new EvaluationSegment(
+            null,
+            [[new EvaluationCondition(
+                ['context','user', 'user_properties', 'boolProp'],
+                'is',
+                ['true']
+            )]],
+            'on'
+        );
+
+        $falseSegment = new EvaluationSegment(
+            null,
+            [[new EvaluationCondition(
+                ['context','user', 'user_properties', 'boolProp'],
+                'is',
+                ['false']
+            )]],
+            'off'
+        );
+
+        $segments = [$trueSegment, $falseSegment];
+        $flag = new EvaluationFlag('test-bool', $variants, $segments);
+        $flags = ['test-bool' => $flag];
+
+        // Test case 1: PHP boolean true
+        $context = ['user' => ['user_properties' => ['boolProp' => true]]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('on', $results['test-bool']->key);
+
+        // Test case 2: PHP boolean false
+        $context = ['user' => ['user_properties' => ['boolProp' => false]]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('off', $results['test-bool']->key);
+
+        // Test case 3: String 'true'
+        $context = ['user' => ['user_properties' => ['boolProp' => 'true']]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('on', $results['test-bool']->key);
+
+        // Test case 4: String 'false'
+        $context = ['user' => ['user_properties' => ['boolProp' => 'false']]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('off', $results['test-bool']->key);
+
+        // Test case 5: String 'True' (capitalized)
+        $context = ['user' => ['user_properties' => ['boolProp' => 'True']]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('on', $results['test-bool']->key);
+
+        // Test case 6: String 'False' (capitalized)
+        $context = ['user' => ['user_properties' => ['boolProp' => 'False']]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('off', $results['test-bool']->key);
+
+        // Test case 7: Numeric 1
+        $context = ['user' => ['user_properties' => ['boolProp' => 1]]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('on', $results['test-bool']->key);
+
+        // Test case 8: Numeric 0
+        $context = ['user' => ['user_properties' => ['boolProp' => 0]]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('off', $results['test-bool']->key);
+
+        // Test case 9: String '1'
+        $context = ['user' => ['user_properties' => ['boolProp' => '1']]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('on', $results['test-bool']->key);
+
+        // Test case 10: String '0'
+        $context = ['user' => ['user_properties' => ['boolProp' => '0']]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('off', $results['test-bool']->key);
+    }
+
+    public function testBooleanIsNotMatching()
+    {
+        $variants = [
+            'on' => new EvaluationVariant('on'),
+            'off' => new EvaluationVariant('off')
+        ];
+
+        $segment = new EvaluationSegment(
+            null,
+            [[new EvaluationCondition(
+                ['context','user', 'user_properties', 'boolProp'],
+                'is not',
+                ['true']
+            )]],
+            'on'
+        );
+
+        $flag = new EvaluationFlag('test-bool-not', $variants, [$segment]);
+        $flags = ['test-bool-not' => $flag];
+
+        // Test negative cases
+        $context = ['user' => ['user_properties' => ['boolProp' => false]]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('on', $results['test-bool-not']->key);
+
+        $context = ['user' => ['user_properties' => ['boolProp' => 'false']]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('on', $results['test-bool-not']->key);
+
+        $context = ['user' => ['user_properties' => ['boolProp' => 'False']]];
+        $results = $this->engine->evaluate($context, $flags);
+        $this->assertEquals('on', $results['test-bool-not']->key);
+    }
+}
diff --git a/tests/EvaluationCore/TopologicalSortTest.php b/tests/EvaluationCore/TopologicalSortTest.php
index d994aa8..40557f4 100644
--- a/tests/EvaluationCore/TopologicalSortTest.php
+++ b/tests/EvaluationCore/TopologicalSortTest.php
@@ -2,6 +2,7 @@
 
 namespace AmplitudeExperiment\Test\EvaluationCore;
 
+use AmplitudeExperiment\EvaluationCore\Types\EvaluationFlag;
 use Exception;
 use PHPUnit\Framework\TestCase;
 use function AmplitudeExperiment\EvaluationCore\topologicalSort;
@@ -294,19 +295,19 @@ function testComplexNoCycleStartingWithRoot()
     private function topologicalSortInternal($flags, $flagKeys = null): array
     {
         $flagsMap = array_reduce($flags, function ($map, $flag) {
-            $map[$flag["key"]] = $flag;
+            $map[$flag->key] = $flag;
             return $map;
         }, []);
         return topologicalSort($flagsMap, $flagKeys);
     }
 
-    private function flag($key, $dependencies = null): array
+    private function flag($key, $dependencies = null): EvaluationFlag
     {
-        return [
-            'key' => strval($key),
-            'variants' => [],
-            'segments' => [],
-            'dependencies' => is_array($dependencies) ? array_map('strval', $dependencies) : null,
-        ];
+        $flag = new EvaluationFlag($key, [], []);
+        $flag->key = strval($key);
+        $flag->variants = [];
+        $flag->segments = [];
+        $flag->dependencies = is_array($dependencies) ? array_map('strval', $dependencies) : null;
+        return $flag;
     }
 }