<?php

class Arr{
    private $obj;

    public function __construct($array)
    {
        $this->obj = $array;
        return $this;
    }

    public function each($func)
    {
        foreach($this->obj as $i){
            call_user_func($func, $i);
        }
    }

    public function filter($func)
    {
        $clone = clone $this;
        $clone->obj = array_filter($clone->obj, $func);
        return $clone;
    }

    public function first($num = 1)
    {
        if($num == 1){
            return $this->obj[0];
        }else{
            $clone = clone $this;
            $clone->obj = array_slice($clone->obj, 0, $num);
            return $clone;
        }
    }

    public function last($num = 1)
    {
        if($num == 1){
            $result = end($this->obj);
            reset($this->obj);
            return $result;
        }else{
            $clone = clone $this;
            $clone->obj = array_slice($clone->obj, -$num);
            return $clone;
        }
    }

    public function has($item)
    {
        return in_array($item, $this->obj);
    }

    public function in($container)
    {
        if(is_array($container)){
            return in_array($this->obj, $container);
        }elseif($container instanceof Arr){
            return $container->has($this->obj);
        }
    }

    public function join($str = '')
    {
        return s(implode($str, $this->obj));
    }

    public function map($func)
    {
        $clone = clone $this;
        $clone->obj = array_map($func, $clone->obj);
        return $clone;
    }

    public function max()
    {
        return max($this->obj);
    }

    public function min()
    {
        return min($this->obj);
    }

    public function reverse()
    {
        $clone = clone $this;
        $clone->obj = array_reverse($clone->obj);
        return $clone;
    }

    public function sample($num = 1)
    {
        $clone = clone $this;
        shuffle($clone->obj);
        $clone->obj = array_slice($clone->obj, 0, $num);
        return $clone;
    }

    public function slice($offset, $length)
    {
        $clone = clone $this;
        $clone->obj = array_slice($clone->obj, $offset, $length);
        return $clone;
    }

    public function sort($arg)
    {
        $clone = clone $this;
        if(is_string($arg)){
            if($arg == "-1"){
                $clone->obj = array_reverse($clone->obj);
            }elseif(s($arg)->ltrim()->startwith("|")){
//                preg_match("/\|(.*)\|(.*)/is", $arg, $out);
//                list($z, $a, $b) = $out;
            }
        }elseif(is_callable($arg)){
            usort($clone->obj, $arg);
        }
        return $clone;
    }

    public function sum()
    {
        return array_sum($this->obj);
    }

    public function to_array()
    {
        return $this->obj;
    }

    public function count($item = null){
        if($item == null){
            return count($this->obj);
        }else{
            $count = 0;
            foreach($this->obj as $i){
                if($i === $item){
                    $count++;
                }
            }
            return $count;
        }
    }

    public function __toString()
    {
        return sprintf($this->obj);
    }
}

class Str{
    private $obj;

    public function __construct($str)
    {
        $this->obj = $str;
        return $this;
    }

    public function endwith($str)
    {
        return substr($this->obj, -strlen($str)) == $str;
    }

    public function endiwith($str)
    {
        return strripos($this->obj, $str, 0) === strlen($this->obj) - strlen($str);
    }

    public function first($num = 1)
    {
        $clone = clone $this;
        $clone->obj = substr($clone->obj, 0, $num);
        return $clone;
    }

    public function has($str){
        return strpos($this->obj, $str) !== false;
    }

    public function in($container)
    {
        return strpos($container, $this->obj) !== false;
    }

    public function last($num = 1)
    {
        $clone = clone $this;
        $clone->obj = substr($clone->obj, -$num);
        return $clone;
    }

    public function ltrim($arg = null)
    {
        $clone = clone $this;
        if($arg){
            $clone->obj = ltrim($clone->obj, $arg);
        }else{
            $clone->obj = ltrim($clone);
        }
        return $clone;
    }

    public function replace($pattern, $replacement){
        $clone = clone $this;
        if($pattern[0] == '/'){
            $clone->obj = preg_replace($pattern, $replacement, $clone->obj);
        }else{
            $clone->obj = preg_replace("/{$pattern}/s", $replacement, $clone->obj);
        }
        return $clone;
    }

    public function replace_once($pattern, $replacement)
    {
        $clone = clone $this;
        if($pattern[0] == '/'){
            $clone->obj = preg_replace($pattern, $replacement, $clone->obj, 1);
        }else{
            $clone->obj = preg_replace("/{$pattern}/s", $replacement, $clone->obj, 1);
        }
        return $clone;
    }

    public function trim($arg = null)
    {
        $clone = clone $this;
        if($arg){
            $clone->obj = trim($clone->obj, $arg);
        }else{
            $clone->obj = trim($clone);
        }
        return $clone;
    }

    public function rtrim($arg = null)
    {
        $clone = clone $this;
        if($arg){
            $clone->obj = rtrim($clone->obj, $arg);
        }else{
            $clone->obj = rtrim($clone);
        }
        return $clone;
    }

    public function sample($num = 1)
    {
        $clone = clone $this;
        $clone->obj = substr(str_shuffle($clone->obj), 0, $num);
        return $clone;
    }

    public function split($arg = '')
    {
        if(is_integer($arg)){
            return a(str_split($this->obj, $arg));
        }elseif(is_string($arg)){
            if($arg == ''){
                return a(str_split($this->obj));
            }else{
                return a(explode($arg, $this->obj));
            }
        }
        return null;
    }

    public function startwith($str)
    {
        return strpos($this->obj, $str) === 0;
    }

    public function startiwith($str)
    {
        return stripos($this->obj, $str) === 0;
    }

    public function count($str = null)
    {
        if($str == null){
            return strlen($this->obj);
        }else{
            return (count(preg_split("/{$str}/s", $this->obj)) - 1);
        }
    }

    public function len(){return strlen($this->obj);}

    public function __toString()
    {
        return $this->obj;
    }
}


function a($array){return new Arr($array);}
function s($str){return new Str($str);}

$a = a([1, 2, 3]);
$s = s("abcdefa");
//print_r($s->split()->last(3)->to_array());
//print_r($s->count(s('ba')->first(2)));
echo $s->replace("/\w/", "3333333333");