0
function KeepSamePage($text)
 {
$sb_w = $oPdf->GetStringWidth($text);

$num_lines = explode("\n",$text);

$total = 0;
foreach($num_lines as $line)
 {

  $y = $oPdf->GetY();
  $page_height = 11 * 25.4;

  $this_width = $oPdf->GetStringWidth(strip_tags($line));
  $extra_line = floor($this_width / $w);
  $is_line = $this_width / ($w - 1);
  $is_line = $this_width == 0 ? 1 + $extra_line : ceil($is_line) + $extra_line;
  $total = $total + $is_line;
 }

  $sb_height = $total * 5;
  if(($page_height - $y) < $sb_height){ $oPdf->AddPage(); }
}

KeepSamePage($signature_block);

I'm using FPDF and I'm creating a function to keep the signature page of a letter all on the same page. This checks to see if it would go to the next page and if soo, then it does an AddPage();

The issue I'm having is that when I don't have it in a function, it works perfectly, but when I put it within a function, I get errors when calling the methods in the class represented by $oPdf.

So, my question generally is this: Is it possible to have a regular function in PHP call a class method as I have below? If it is possible, what am I doing wrong?

ERROR GENERATED IS:

Fatal error: Call to a member function GetStringWidth() on a non-object in /home/jarodmo/public_html/cms/attorney_signature_block.php on line 18

Oh, and an explanation of my function just in case you're interested or someone else finds it.

Text has \n for new lines in it so the PDF will put the text of the signature block on the next line. Each new array element should be a new line, so I would need to multiply the number of lines by my line height, 5 in this case. (See $total * 5).

I check to see where we are on the page, find the difference between the page height and the Y position, then check that against the height of the signature block. If the signature block is bigger, then it wouldn't fit and I know we need a manual page break.

Also, because I do the explode with the \n to see the lines, I also have to check to make sure that none of the lines is still wider than the page otherwise it would word wrap and really be 2 lines (or more) where I was only counting it as 1 because it was just one array element. I know a signature block shouldn't have text wide enough to be on 2 lines, but I wrote this to be applicable for more than just signature blocks. I wanted to be able to call this function anywhere I wanted to make sure certain text stayed on the same page. Call the function, check the text I'm about to write to the PDF and move on knowing that the desired text would all be on the same page.

Thanks for all of the help and comments. SO is the best.

PeeHaa
  • 66,697
  • 53
  • 182
  • 254
j_allen_morris
  • 477
  • 2
  • 7
  • 24
  • I don't see where you initialize the $oPdf object. Is this all your code? – juanOS Mar 02 '13 at 03:49
  • Is your $oPdf object generated outside the function? If so, you will have to use something like global $oPdf in your function. – Oliver Mar 02 '13 at 03:49
  • Oliver - what do you mean by global $oPdf? I went to the fpdf.pdf file where the class is located and defined the method as public GetStringWidth() but that didn't do anything. – j_allen_morris Mar 02 '13 at 03:54
  • juan - no it is not all my code. I didn't include the rest of the hundreds of lines because I said it all works when I have it not inside the function. Trying to save some space and drill the question down to the actual problem. – j_allen_morris Mar 02 '13 at 03:55
  • No no.. don't global $oPdf. Just pass it to the function as a parameter. Read this: http://stackoverflow.com/questions/5166087/php-global-in-functions – Kai Qing Mar 02 '13 at 03:56
  • Kai Qing - you were absolutely right. I've been programming simple PHP apps for years but because programming isn't my job (I don't even work in tech industry) I never got into the classes, OOP, etc. Now that I have a project for myself that needs it, I'm blown away by php classes. – j_allen_morris Mar 02 '13 at 04:01
  • Allen, You should really ready the link I posted in my answer. You need to understand how scope works for it to make sense. – Ares Mar 02 '13 at 04:04

3 Answers3

1
$oPdf 

is not defined on your code. You need to define it, and maybe read PHP variable scope.

You are trying to access methods of the $oPdf object in your function, but your function has no idea what $oPdf is, thus, the error message.

Ares
  • 5,800
  • 3
  • 32
  • 49
  • Ares - Sorry, I forgot to mention that this code is inside a PHP file that is included into my larger file. In the larger file, $oPdf is initialized. Like I said, it all works when not calling to a method from within a function. – j_allen_morris Mar 02 '13 at 03:53
  • How is $oPdf defined? Not because it is defined in an included file means that it is included in the scope of the function. – Ares Mar 02 '13 at 03:54
  • It's not initialized in your function though. That's what ares is saying. You need to either pass the reference to the function: function KeepSamePage($text, $oPdf) or instantiate the class inside the function – Kai Qing Mar 02 '13 at 03:55
  • Kai Qing - IF you'll create an answer saying I need to define $oPdf in my function as global, I'll select it as the answer because that is what fixed it. THANKS!!! – j_allen_morris Mar 02 '13 at 04:02
  • j_allen, yes defining it as global would make it work. However, I think it is not the "correct" answer. You can fix your problem using the "right tools" or you can use duct tape. Your choice. You should also read http://stackoverflow.com/questions/5166087/php-global-in-functions – Ares Mar 02 '13 at 04:06
  • I see the point now of globals and how people consider them evil. It can get confusing because you see the function, have 1 variable passed to it and then want to use that in another application but unless that other application has the exact same global variable, the function won't perform correctly and it will get very confusing as to why. In my case, I didn't want to change the variable, but use it to access the methods of the class. I'd rather use best practices even though this code will never be commercial code. – j_allen_morris Mar 02 '13 at 04:30
1

you have to do something like this.

function KeepSamePage($text) {
$oPdf = new your_string_class();
$sb_w = $oPdf->GetStringWidth($text);
}

or

$oPdf = new your_string_class();
function KeepSamePage($text, $oPdf) {
$sb_w = $oPdf->GetStringWidth($text);
}
Dino Babu
  • 5,506
  • 3
  • 21
  • 33
0

Try the following:

function KeepSamePage($text) {
    global $oPdf;

    …
}

The problem is, that the object is defined outside your function and you will have to allow your function to access it.

// Edit: If you want to avoid global for whatever reason, you will have to pass your object to the function like this:

function KeepSamePage($text, $oPdf) {
    …
    // IMPORTANT! $oPdf has changed in this function, so you will have to give it back
    return $oPdf;
}

You can call your function like this:

$oPdf = KeepSamePage($signature_block, $oPdf);

The advantage is, that you see in the main thread, that your function might has changed the object.

// Edit 2: I think, I was wrong on the edit1 in your case. As you pass the complete object to the function every change does apply to the object, so the changes will still be existant without giving back the result. If this was a variable that was defined in the main thread, you would have to give back the new value:

$a = 1;

function result1($a) {
    ++$a;
}

function result2($a) {
    return ++$a;
}

echo $a."\n"; // 1
result1($a);
echo $a."\n"; // 1
$a = result2($a);
echo $a."\n"; // 2
Oliver
  • 2,764
  • 1
  • 13
  • 26
  • http://stackoverflow.com/questions/5166087/php-global-in-functions - that about sums it all up – Kai Qing Mar 02 '13 at 04:00
  • Remember folks: "Think globally. Act within local variable scope" – Ares Mar 02 '13 at 04:02
  • Ehm, You can also pass the object as reference, BUT then, you will have to give it back to the main script, because it is changed. The behaviour you called "bad idea" is absolutely intended in this scope. – Oliver Mar 02 '13 at 04:07
  • I'm not sure I follow why what Oliver said is a bad idea? Yes, I've gone to the link but haven't been able to read the entire thing in the last 5 minutes. – j_allen_morris Mar 02 '13 at 04:07
  • Oliver, is there something I should do to be safer when using your solution of global $oPdf – j_allen_morris Mar 02 '13 at 04:10
  • PHP works on pass-by-reference for objects. Passing it in would *technically* work correctly and avoid the global. And until the last line, you aren't modifying it. I personally would pass it in. – Tyler Carter Mar 02 '13 at 04:13
  • This has nothing to do with security, but with code design. You give your function the ability to change the object. So if you read just the main thread, you might wonder, why your object has changed. Anyway in this case, this behaviour is absolutely intended. – Oliver Mar 02 '13 at 04:16
  • I'm not necessarily looking to change $oPdf, but use it to call to methods within the class. I changed it up to pass the variable to it rather than define it globally and it still works. – j_allen_morris Mar 02 '13 at 04:25
  • I added an example, how to pass the variable and give it back. – Oliver Mar 02 '13 at 04:27
  • Oliver, how will $oPdf->AddPage(); give me problems? If you mean cause it to not work, that hasn't been the case. If you mean other problems, please explain. Thanks. – j_allen_morris Mar 02 '13 at 04:33