Substring function in PHP I wrote this function to test if one string is a substring of another.

I'm curious to get some feedback on the implementation - does my solution seem reasonable? Is the code "well written"? Is there a better way of doing this?

&lt;?php
function isSubStr($a, $b){
    if(!strpos($a, $b[0])){
        return false;
    }
    $result = true;
    $start = strpos($a, $b[0]);
    for ($pos = 0; $pos &lt; strlen($b); $pos++){
            if($b[$pos] != $a[$start + $pos]){
                $result = false;
            }
    }
    return $result;
}


Tests below:

&lt;?php
require 'solution.php';
use PHPUnit\Framework\TestCase;

class myTests extends TestCase {
  public function testExamples() {
        $this-&gt;assertEquals(isSubStr('cat', 'at'), true);
        $this-&gt;assertEquals(isSubStr('cat', 'fluffy'), false);
        $this-&gt;assertEquals(isSubStr('cheeze', 'ee'), true);
        $this-&gt;assertEquals(isSubStr('snow', 'o'), true);
        $this-&gt;assertEquals(isSubStr('octopus', 'top'), true);
        $this-&gt;assertEquals(isSubStr('octopus', 'zzz'), false);
  }
}
Beside the obvious fact that you're reinventing the wheel as this functionality is already present in php, here are some comments to your code:


Strange to use strpos() – If you want to reinvent the wheel, then I wouldn't use strpos() at all.
Doesn't restart checks – As commented upon by mdfst13, cases like ababc vs abc fails, as you don't restart the test if the first candidate fails.
Too long substrings gives index errors – Testing with octopus vs pussy results in index errors on the source string.
$a and $b are not really good names – They don't convey anything regarding their intended purpose, as $source and $substr would do.* 
No comments – It always nice to have a little comments to indicate what you are trying to achieve in a code block.


So an even more basic version which implements these comments could look like:

function isSubStr($source, $substr) {
  $len_src = strlen($source);
  $len_sub = strlen($substr);
  $max_start_pos = $len_src - $len_sub;

  // If longer, there isn't room for it
  if ($max_start_pos &lt; 0) {
    return false;
  }

  // Find start position for substring
  $pos = 0;
  while ($pos &lt;= $max_start_pos) {

    // Check if we have a valid start position
    if ($source[$pos] == $substr[0]) {

       // Assume it is a good candidate, and verify this
       $foundCandidate = true;

      // Check for equality between source and substring,
      // and verify length of both strings
      for ($subIdx = 0, $orgIdx = $pos; 
           $orgIdx &lt; $len_src &amp;&amp; $subIdx &lt; $len_sub;
           $orgIdx++, $subIdx++) {

        if ($source[$orgIdx] != $substr[$subIdx]) {
          $foundCandidate = false;
          break;
        } 
      }

      // If we exited previous loop due to exhausting the substring,
      // and not have a falsified candidate we have a match 
      if ($foundCandidate &amp;&amp; $len_sub == $subIdx) {
            return true;
      }
    }

    $pos++;
  }

  // Passed max start position without finding start of substr
  if ($pos &gt; $max_start_pos) {
    return false;
  }
}


This code passes for all of the following cases:

public function testExamples() {
      $this-&gt;assertEquals(isSubStr('cat', 'at'), true);
      $this-&gt;assertEquals(isSubStr('cat', 'fluffy'), false);
      $this-&gt;assertEquals(isSubStr('cheeze', 'ee'), true);
      $this-&gt;assertEquals(isSubStr('snow', 'o'), true);
      $this-&gt;assertEquals(isSubStr('octopus', 'top'), true);
      $this-&gt;assertEquals(isSubStr('octopus', 'zzz'), false);
      $this-&gt;assertEquals(isSubStr('octopus', 'pussy'), false);
      $this-&gt;assertEquals(isSubStr('octopus', 'tops'), false);
      $this-&gt;assertEquals(isSubStr('ababc', 'abc'), true);
      $this-&gt;assertEquals(isSubStr('abc', 'abc'), true); 
}